]> git.pld-linux.org Git - packages/busybox.git/commitdiff
- http://www.zelow.no/floppyfw/download/Development/Patches/busybox-snapshot/busybox...
authorareq <areq@pld-linux.org>
Sun, 5 Jun 2005 14:49:24 +0000 (14:49 +0000)
committercvs2git <feedback@pld-linux.org>
Sun, 24 Jun 2012 12:13:13 +0000 (12:13 +0000)
- from busybox snapshot

Changed files:
    busybox-cvs-20050604.patch -> 1.1
    busybox-lzmacat.diff -> 1.1

busybox-cvs-20050604.patch [new file with mode: 0644]
busybox-lzmacat.diff [new file with mode: 0644]

diff --git a/busybox-cvs-20050604.patch b/busybox-cvs-20050604.patch
new file mode 100644 (file)
index 0000000..5da0ac2
--- /dev/null
@@ -0,0 +1,44250 @@
+diff -Nur busybox-1.00/AUTHORS busybox/AUTHORS
+--- busybox-1.00/AUTHORS       2004-07-26 20:57:49.000000000 +0200
++++ busybox/AUTHORS    2005-06-04 08:20:22.000000000 +0200
+@@ -2,12 +2,15 @@
+ If you have code in BusyBox, you should be listed here.  If you should be
+ listed, or the description of what you have done needs more detail, or is
+-incorect, _please_ let me know.
++incorrect, _please_ let me know.
+  -Erik
+ -----------
++Peter Willis <psyphreak@phreaker.net>
++    eject
++
+ Emanuele Aina <emanuele.aina@tiscali.it>
+     run-parts
+@@ -29,6 +32,9 @@
+ John Beppu <beppu@codepoet.org>
+     du, nslookup, sort
++David Brownell <dbrownell@users.sourceforge.net>
++    zcip
++
+ Brian Candler <B.Candler@pobox.com>
+     tiny-ls(ls)
+@@ -69,6 +75,12 @@
+ Matt Kraai <kraai@alumni.cmu.edu>
+     documentation, bugfixes, test suite
++Rob Landley <rob@landley.net>
++    sed (major rewrite in 2003, and I now maintain the thing).
++    bunzip2 (complete from-scratch rewrite, then mjn3 optimized the result.)
++    sort (more or less from scratch rewrite in 2004, I now maintain it).
++    I've patched lots of other applets, but don't maintain 'em.
++
+ Stephan Linz <linz@li-pro.net>
+     ipcalc, Red Hat equivalence
+@@ -76,13 +88,14 @@
+     tr
+ Glenn McGrath <bug1@iinet.net.au>
+-    Common unarchving code and unarchiving applets, ifupdown, ftpgetput,
+-    nameif, sed, patch, fold, install, uudecode. 
+-    Various bugfixes, review and apply numerous patches. 
++    Common unarchiving code and unarchiving applets, ifupdown, ftpgetput,
++    nameif, sed, patch, fold, install, uudecode.
++    Various bugfixes, review and apply numerous patches.
+ Manuel Novoa III <mjn3@codepoet.org>
+     cat, head, mkfifo, mknod, rmdir, sleep, tee, tty, uniq, usleep, wc, yes,
+-    mesg, vconfig, make_directory, parse_mode, dirname, mode_string,
++    mesg, vconfig, nice, renice,
++    make_directory, parse_mode, dirname, mode_string,
+     get_last_path_component, simplify_path, and a number trivial libbb routines
+     also bug fixes, partial rewrites, and size optimizations in
+@@ -115,6 +128,9 @@
+ Gyepi Sam <gyepi@praxis-sw.com>
+     Remote logging feature for syslogd
++Rob Sullivan <cogito.ergo.cogito@gmail.com>
++    comm
++
+ Linus Torvalds <torvalds@transmeta.com>
+     mkswap, fsck.minix, mkfs.minix
+@@ -129,5 +145,6 @@
+     tarcat (since removed), loadkmap, various fixes, Debian maintenance
+ Tito Ragusa <farmatito@tiscali.it>
+-    devfsd and size optimizations in strings, openvt, chvt, deallocvt, hdparm and fdformat.
++    devfsd and size optimizations in strings, openvt, chvt, deallocvt, hdparm,
++    fdformat, lsattr, chattr, id and eject.
+diff -Nur busybox-1.00/Makefile busybox/Makefile
+--- busybox-1.00/Makefile      2004-10-08 09:45:08.000000000 +0200
++++ busybox/Makefile   2005-06-04 08:20:22.000000000 +0200
+@@ -22,7 +22,7 @@
+ #--------------------------------------------------------------
+ noconfig_targets := menuconfig config oldconfig randconfig \
+       defconfig allyesconfig allnoconfig clean distclean \
+-      release tags  
++      release tags
+ ifndef TOPDIR
+ TOPDIR=$(CURDIR)/
+@@ -42,13 +42,12 @@
+ DIRS:=applets archival archival/libunarchive coreutils console-tools \
+       debianutils editors findutils init miscutils modutils networking \
+       networking/libiproute networking/udhcp procps loginutils shell \
+-      sysklogd util-linux libpwdgrp coreutils/libcoreutils libbb
++      sysklogd util-linux e2fsprogs libpwdgrp coreutils/libcoreutils libbb
+ SRC_DIRS:=$(patsubst %,$(top_srcdir)/%,$(DIRS))
+ ifeq ($(strip $(CONFIG_SELINUX)),y)
+-CFLAGS += -I/usr/include/selinux
+-LIBRARIES += -lsecure
++LIBRARIES += -lselinux
+ endif
+ CONFIG_CONFIG_IN = $(top_srcdir)/sysdeps/$(TARGET_OS)/Config.in
+@@ -130,7 +129,7 @@
+ busybox.links: $(top_srcdir)/applets/busybox.mkll include/config.h $(top_srcdir)/include/applets.h
+       - $(SHELL) $^ >$@
+-install: applets/install.sh busybox busybox.links
++install: $(top_srcdir)/applets/install.sh busybox busybox.links
+       $(SHELL) $< $(PREFIX)
+ ifeq ($(strip $(CONFIG_FEATURE_SUID)),y)
+       @echo
+@@ -147,7 +146,7 @@
+       rm -f $(PREFIX)/bin/busybox
+       for i in `cat busybox.links` ; do rm -f $(PREFIX)$$i; done
+-install-hardlinks: applets/install.sh busybox busybox.links
++install-hardlinks: $(top_srcdir)/applets/install.sh busybox busybox.links
+       $(SHELL) $< $(PREFIX) --hardlinks
+ check: busybox
+diff -Nur busybox-1.00/TODO busybox/TODO
+--- busybox-1.00/TODO  2004-05-01 02:49:49.000000000 +0200
++++ busybox/TODO       2005-06-04 08:20:22.000000000 +0200
+@@ -2,10 +2,106 @@
+ Stuff that needs to be done
+-----
+-tr - missing SuS3 features in busybox 1.0pre10 
++tr - missing SuS3 features in busybox 1.0pre10
+ tr doesnt support [:blank:], [:digit:] or other predefined classes, [=equiv=]
+ support is also missing.
+ ----
+- 
++find
++  doesn't understand () or -exec, and these are actually used out in the real
++  world.  The "make uninstall" of lots of things (including busybox itself)
++  breaks because of this, and sometimes even "make install" (like udev).
++----
++comm
++  Perl needs "comm" to build.  It's small and simple, but we haven't got it.
++---
++sh
++  The command shell situation is a big mess.  We have three or four different
++  shells that don't really share any code, and the "standalone shell" doesn't
++  work all that well (especially not in a chroot environment), due to apps not
++  being reentrant.  Unifying the various shells and figuring out a configurable
++  way of adding the minimal set of bash features a given script uses is a big
++  job, but it be a big improvement.
++---
++gzip
++  Can't handle compressing multiple files at once.  (I don't mean making a
++  multiple file archive, I mean compressing more than one file at a time.)
++  Some global variables aren't re-initialized between runs.
++---
++gunzip
++  same problem as gzip.  "gunzip one.gz two.gz three.gz" doesn't work for
++  two.gz and three.gz due to global variables not getting reset.
++---
++diff
++  We should have a diff -u command.  We have patch, we should have diff
++  (we only need to support unified diffs though).
++---
++patch
++  should have -i support, and simple fuzz factor support to apply patches
++  at an offset shouldn't take up too much space.
++---
++man
++  It would be nice to have a man command.  Not one that handles troff or
++  anything, just one that can handle preformatted ascii man pages, possibly
++  compressed.  This could probably be a script in the extras directory that
++  calls cat/zcatbzcat | more
++---
++less
++  More sucks if you're used to less.  A tiny less implementation would be
++  very nice.
++---
++bzip2
++  Compression-side support.
++
++
++Architectural issues:
++
++Do a SUSv3 audit
++  Look at the full Single Unix Specification version 3 (available online at
++  "http://www.opengroup.org/onlinepubs/009695399/nfindex.html") and
++  figure out which of our apps are compliant, and what we're missing that
++  we might actually care about.
++
++  Even better would be some kind of automated compliance test harness that
++  exercises each command line option and the various corner cases.
++--
++Unify archivers
++  Lots of archivers have the same general infrastructure.  The directory
++  traversal code should be factored out, and the guts of each archiver could
++  be some setup code and a series of callbacks for "add this file",
++  "add this directory", "add this symlink" and so on.
++
++  This could clean up tar and zip, and make it cheaper to add cpio and ar
++  write support, and possibly even cheaply add things like mkisofs someday,
++  if it becomes relevant.
++---
++Text buffer support.
++  Several existing applets and potential additions (sort, vi, less...) read
++  a whole file into memory and act on it.  There might be an opportunity
++  for shared code in there that could be moved into libbb...
++---
++Individual compilation of applets.
++  It would be nice if busybox had the option to compile to individual applets,
++  for people who want an alternate implementation less bloated than the gnu
++  utils (or simply with less political baggage), but without it being one big
++  executable.
++
++  Turning libbb into a real dll is another possibility, especially if libbb
++  could export some of the other library interfaces we've already more or less
++  got the code for (like zlib).
++---
++buildroot - Make a "dogfood" option
++  Busybox is now capable of replacing most gnu packages for real world use,
++  such as developing software or in a live CD.  A system built from busybox
++  (1.00 with updated sort.c), uclibc 0.9.27, gcc, binutils, make, and a few
++  other development tools (http://www.landley.net/code/firmware has an example
++  system using autoconf, automake, bison, flex, libtools, m4, zlib,
++  and groff: dunno what subset of that is actually necessary) is capable of
++  rebuilding itself, from scratch, under itself.
++
++  It would be a good "eating our own dogfood" test if buildroot had the option
++  of using busybox instead of bzip2, coreutils, file, findutils, gawk, grep,
++  inetutils, modutils, net-tools, procps, sed, shadow, sysklogd, sysvinit, tar,
++  util-linux, and vim.  Anything that's wrong with the resulting system, we
++  can fix.  (It would be nice to be able to upgrade busybox to be able to
++  replace bash, diffutils, gzip, less, and patch as well.)
+diff -Nur busybox-1.00/applets/busybox.c busybox/applets/busybox.c
+--- busybox-1.00/applets/busybox.c     2004-03-15 09:28:15.000000000 +0100
++++ busybox/applets/busybox.c  2005-06-04 08:20:20.000000000 +0200
+@@ -144,25 +144,25 @@
+               output_width -= 20;
+ #endif
+-              fprintf(stderr, "%s\n\n"
+-                              "Usage: busybox [function] [arguments]...\n"
+-                              "   or: [function] [arguments]...\n\n"
+-                              "\tBusyBox is a multi-call binary that combines many common Unix\n"
+-                              "\tutilities into a single executable.  Most people will create a\n"
+-                              "\tlink to busybox for each function they wish to use, and BusyBox\n"
+-                              "\twill act like whatever it was invoked as.\n"
+-                              "\nCurrently defined functions:\n", bb_msg_full_version);
++              printf("%s\n\n"
++                     "Usage: busybox [function] [arguments]...\n"
++                     "   or: [function] [arguments]...\n\n"
++                     "\tBusyBox is a multi-call binary that combines many common Unix\n"
++                     "\tutilities into a single executable.  Most people will create a\n"
++                     "\tlink to busybox for each function they wish to use and BusyBox\n"
++                     "\twill act like whatever it was invoked as!\n"
++                     "\nCurrently defined functions:\n", bb_msg_full_version);
+               while (a->name != 0) {
+                       col +=
+-                              fprintf(stderr, "%s%s", ((col == 0) ? "\t" : ", "),
+-                                              (a++)->name);
++                              printf("%s%s", ((col == 0) ? "\t" : ", "),
++                                     (a++)->name);
+                       if (col > output_width && a->name != 0) {
+-                              fprintf(stderr, ",\n");
++                              printf(",\n");
+                               col = 0;
+                       }
+               }
+-              fprintf(stderr, "\n\n");
++              printf("\n\n");
+               exit(0);
+       }
+diff -Nur busybox-1.00/archival/ar.c busybox/archival/ar.c
+--- busybox-1.00/archival/ar.c 2004-10-07 02:35:59.000000000 +0200
++++ busybox/archival/ar.c      2005-06-04 08:20:08.000000000 +0200
+@@ -56,19 +56,21 @@
+ #define AR_OPT_PRESERVE_DATE  0x08
+ #define AR_OPT_VERBOSE                        0x10
+ #define AR_OPT_CREATE                 0x20
++#define AR_OPT_INSERT                 0x40
+ extern int ar_main(int argc, char **argv)
+ {
+       archive_handle_t *archive_handle;
+       unsigned long opt;
++      char *msg_unsupported_err = "Archive %s not supported.  Install binutils 'ar'.";
+       char magic[8];
+       archive_handle = init_handle();
+       bb_opt_complementaly = "p~tx:t~px:x~pt";
+-      opt = bb_getopt_ulflags(argc, argv, "ptxovc");
++      opt = bb_getopt_ulflags(argc, argv, "ptxovcr");
+-      if ((opt & 0x80000000UL) || (optind == argc)) {
++      if ((opt & BB_GETOPT_ERROR) || (opt == 0) || (optind == argc)) {
+               bb_show_usage();
+       }
+@@ -88,7 +90,10 @@
+               archive_handle->action_header = header_verbose_list_ar;
+       }
+       if (opt & AR_OPT_CREATE) {
+-              bb_error_msg_and_die("Archive creation not supported.  Install binutils 'ar'.");
++              bb_error_msg_and_die(msg_unsupported_err, "creation");
++      }
++      if (opt & AR_OPT_INSERT) {
++              bb_error_msg_and_die(msg_unsupported_err, "insertion");
+       }
+       archive_handle->src_fd = bb_xopen(argv[optind++], O_RDONLY);
+diff -Nur busybox-1.00/archival/dpkg.c busybox/archival/dpkg.c
+--- busybox-1.00/archival/dpkg.c       2004-04-14 19:51:08.000000000 +0200
++++ busybox/archival/dpkg.c    2005-06-04 08:20:08.000000000 +0200
+@@ -58,7 +58,7 @@
+  * I estimate it should be at least 50% bigger than PACKAGE_HASH_PRIME,
+  * as there a lot of duplicate version numbers */
+ #define NAME_HASH_PRIME 16381
+-char *name_hashtable[NAME_HASH_PRIME + 1];
++static char *name_hashtable[NAME_HASH_PRIME + 1];
+ /* PACKAGE_HASH_PRIME, Maximum number of unique packages,
+  * It must not be smaller than STATUS_HASH_PRIME,
+@@ -82,7 +82,7 @@
+       unsigned int num_of_edges:14;
+       edge_t **edge;
+ } common_node_t;
+-common_node_t *package_hashtable[PACKAGE_HASH_PRIME + 1];
++static common_node_t *package_hashtable[PACKAGE_HASH_PRIME + 1];
+ /* Currently it doesnt store packages that have state-status of not-installed
+  * So it only really has to be the size of the maximum number of packages
+@@ -92,7 +92,7 @@
+       unsigned int package:14;        /* has to fit PACKAGE_HASH_PRIME */
+       unsigned int status:14;         /* has to fit STATUS_HASH_PRIME */
+ } status_node_t;
+-status_node_t *status_hashtable[STATUS_HASH_PRIME + 1];
++static status_node_t *status_hashtable[STATUS_HASH_PRIME + 1];
+ /* Even numbers are for 'extras', like ored dependencies or null */
+ enum edge_type_e {
+@@ -137,7 +137,7 @@
+ } deb_file_t;
+-void make_hash(const char *key, unsigned int *start, unsigned int *decrement, const int hash_prime)
++static void make_hash(const char *key, unsigned int *start, unsigned int *decrement, const int hash_prime)
+ {
+       unsigned long int hash_num = key[0];
+       int len = strlen(key);
+@@ -157,7 +157,7 @@
+ }
+ /* this adds the key to the hash table */
+-int search_name_hashtable(const char *key)
++static int search_name_hashtable(const char *key)
+ {
+       unsigned int probe_address = 0;
+       unsigned int probe_decrement = 0;
+@@ -181,7 +181,7 @@
+ /* this DOESNT add the key to the hashtable
+  * TODO make it consistent with search_name_hashtable
+  */
+-unsigned int search_status_hashtable(const char *key)
++static unsigned int search_status_hashtable(const char *key)
+ {
+       unsigned int probe_address = 0;
+       unsigned int probe_decrement = 0;
+@@ -201,7 +201,7 @@
+ }
+ /* Need to rethink version comparison, maybe the official dpkg has something i can use ? */
+-int version_compare_part(const char *version1, const char *version2)
++static int version_compare_part(const char *version1, const char *version2)
+ {
+       int upstream_len1 = 0;
+       int upstream_len2 = 0;
+@@ -268,7 +268,7 @@
+  * if ver1 = ver2 return 0,
+  * if ver1 > ver2 return 1,
+  */
+-int version_compare(const unsigned int ver1, const unsigned int ver2)
++static int version_compare(const unsigned int ver1, const unsigned int ver2)
+ {
+       char *ch_ver1 = name_hashtable[ver1];
+       char *ch_ver2 = name_hashtable[ver2];
+@@ -330,7 +330,7 @@
+       return(version_compare_part(deb_ver1, deb_ver2));
+ }
+-int test_version(const unsigned int version1, const unsigned int version2, const unsigned int operator)
++static int test_version(const unsigned int version1, const unsigned int version2, const unsigned int operator)
+ {
+       const int version_result = version_compare(version1, version2);
+       switch(operator) {
+@@ -366,7 +366,7 @@
+ }
+-int search_package_hashtable(const unsigned int name, const unsigned int version, const unsigned int operator)
++static int search_package_hashtable(const unsigned int name, const unsigned int version, const unsigned int operator)
+ {
+       unsigned int probe_address = 0;
+       unsigned int probe_decrement = 0;
+@@ -405,7 +405,7 @@
+  * FIXME: I don't think this is very efficient, but I thought I'd keep
+  * it simple for now until it proves to be a problem.
+  */
+-int search_for_provides(int needle, int start_at) {
++static int search_for_provides(int needle, int start_at) {
+       int i, j;
+       common_node_t *p;
+       for (i = start_at + 1; i < PACKAGE_HASH_PRIME; i++) {
+@@ -421,7 +421,7 @@
+ /*
+  * Add an edge to a node
+  */
+-void add_edge_to_node(common_node_t *node, edge_t *edge)
++static void add_edge_to_node(common_node_t *node, edge_t *edge)
+ {
+       node->num_of_edges++;
+       node->edge = xrealloc(node->edge, sizeof(edge_t) * (node->num_of_edges + 1));
+@@ -438,7 +438,7 @@
+  * field contains the number of EDGE nodes which follow as part of
+  * this alternative.
+  */
+-void add_split_dependencies(common_node_t *parent_node, const char *whole_line, unsigned int edge_type)
++static void add_split_dependencies(common_node_t *parent_node, const char *whole_line, unsigned int edge_type)
+ {
+       char *line = bb_xstrdup(whole_line);
+       char *line2;
+@@ -537,7 +537,7 @@
+       return;
+ }
+-void free_package(common_node_t *node)
++static void free_package(common_node_t *node)
+ {
+       unsigned short i;
+       if (node) {
+@@ -550,7 +550,7 @@
+       }
+ }
+-unsigned int fill_package_struct(char *control_buffer)
++static unsigned int fill_package_struct(char *control_buffer)
+ {
+       common_node_t *new_node = (common_node_t *) xcalloc(1, sizeof(common_node_t));
+       const char *field_names[] = { "Package", "Version", "Pre-Depends", "Depends",
+@@ -624,7 +624,7 @@
+ }
+ /* if num = 1, it returns the want status, 2 returns flag, 3 returns status */
+-unsigned int get_status(const unsigned int status_node, const int num)
++static unsigned int get_status(const unsigned int status_node, const int num)
+ {
+       char *status_string = name_hashtable[status_hashtable[status_node]->status];
+       char *state_sub_string;
+@@ -646,7 +646,7 @@
+       return(state_sub_num);
+ }
+-void set_status(const unsigned int status_node_num, const char *new_value, const int position)
++static void set_status(const unsigned int status_node_num, const char *new_value, const int position)
+ {
+       const unsigned int new_value_len = strlen(new_value);
+       const unsigned int new_value_num = search_name_hashtable(new_value);
+@@ -682,7 +682,7 @@
+       return;
+ }
+-const char *describe_status(int status_num) {
++static const char *describe_status(int status_num) {
+       int status_want, status_state ;
+       if ( status_hashtable[status_num] == NULL || status_hashtable[status_num]->status == 0 )
+               return "is not installed or flagged to be installed\n";
+@@ -707,7 +707,7 @@
+ }
+-void index_status_file(const char *filename)
++static void index_status_file(const char *filename)
+ {
+       FILE *status_file;
+       char *control_buffer;
+@@ -812,7 +812,7 @@
+ }
+ #endif
+-void write_buffer_no_status(FILE *new_status_file, const char *control_buffer)
++static void write_buffer_no_status(FILE *new_status_file, const char *control_buffer)
+ {
+       char *name;
+       char *value;
+@@ -830,7 +830,7 @@
+ }
+ /* This could do with a cleanup */
+-void write_status_file(deb_file_t **deb_file)
++static void write_status_file(deb_file_t **deb_file)
+ {
+       FILE *old_status_file = bb_xfopen("/var/lib/dpkg/status", "r");
+       FILE *new_status_file = bb_xfopen("/var/lib/dpkg/status.udeb", "w");
+@@ -978,7 +978,7 @@
+  * which a regular depends can be satisfied by a package which we want
+  * to install.
+  */
+-int package_satisfies_dependency(int package, int depend_type)
++static int package_satisfies_dependency(int package, int depend_type)
+ {
+       int status_num = search_status_hashtable(name_hashtable[package_hashtable[package]->name]);
+@@ -995,7 +995,7 @@
+       return 0;
+ }
+-int check_deps(deb_file_t **deb_file, int deb_start, int dep_max_count)
++static int check_deps(deb_file_t **deb_file, int deb_start, int dep_max_count)
+ {
+       int *conflicts = NULL;
+       int conflicts_num = 0;
+@@ -1204,7 +1204,7 @@
+       return(TRUE);
+ }
+-char **create_list(const char *filename)
++static char **create_list(const char *filename)
+ {
+       FILE *list_stream;
+       char **file_list = NULL;
+@@ -1233,7 +1233,7 @@
+ }
+ /* maybe i should try and hook this into remove_file.c somehow */
+-int remove_file_array(char **remove_names, char **exclude_names)
++static int remove_file_array(char **remove_names, char **exclude_names)
+ {
+       struct stat path_stat;
+       int match_flag;
+@@ -1271,7 +1271,7 @@
+       return(remove_flag);
+ }
+-int run_package_script(const char *package_name, const char *script_type)
++static int run_package_script(const char *package_name, const char *script_type)
+ {
+       struct stat path_stat;
+       char *script_path;
+@@ -1290,10 +1290,10 @@
+       return(result);
+ }
+-const char *all_control_files[] = {"preinst", "postinst", "prerm", "postrm",
++static const char *all_control_files[] = {"preinst", "postinst", "prerm", "postrm",
+       "list", "md5sums", "shlibs", "conffiles", "config", "templates", NULL };
+-char **all_control_list(const char *package_name)
++static char **all_control_list(const char *package_name)
+ {
+       unsigned short i = 0;
+       char **remove_files;
+@@ -1310,7 +1310,7 @@
+       return(remove_files);
+ }
+-void free_array(char **array)
++static void free_array(char **array)
+ {
+       if (array) {
+@@ -1327,7 +1327,7 @@
+  * the status_hashtable to retrieve the info. This results in smaller code than
+  * scanning the status file. The resulting list, however, is unsorted.
+  */
+-void list_packages(void)
++static void list_packages(void)
+ {
+         int i;
+@@ -1364,7 +1364,7 @@
+     }
+ }
+-void remove_package(const unsigned int package_num, int noisy)
++static void remove_package(const unsigned int package_num, int noisy)
+ {
+       const char *package_name = name_hashtable[package_hashtable[package_num]->name];
+       const char *package_version = name_hashtable[package_hashtable[package_num]->version];
+@@ -1418,7 +1418,7 @@
+       set_status(status_num, "config-files", 3);
+ }
+-void purge_package(const unsigned int package_num)
++static void purge_package(const unsigned int package_num)
+ {
+       const char *package_name = name_hashtable[package_hashtable[package_num]->name];
+       const char *package_version = name_hashtable[package_hashtable[package_num]->version];
+@@ -1614,7 +1614,7 @@
+       free(info_prefix);
+ }
+-void configure_package(deb_file_t *deb_file)
++static void configure_package(deb_file_t *deb_file)
+ {
+       const char *package_name = name_hashtable[package_hashtable[deb_file->package]->name];
+       const char *package_version = name_hashtable[package_hashtable[deb_file->package]->version];
+diff -Nur busybox-1.00/archival/dpkg_deb.c busybox/archival/dpkg_deb.c
+--- busybox-1.00/archival/dpkg_deb.c   2004-03-15 09:28:16.000000000 +0100
++++ busybox/archival/dpkg_deb.c        2005-06-04 08:20:08.000000000 +0200
+@@ -88,7 +88,7 @@
+               argcount = 2;
+       }
+-      if ((optind + argcount != argc) || (opt & 0x80000000UL)) {
++      if ((optind + argcount != argc) || (opt & BB_GETOPT_ERROR)) {
+               bb_show_usage();
+       }
+diff -Nur busybox-1.00/archival/gzip.c busybox/archival/gzip.c
+--- busybox-1.00/archival/gzip.c       2004-04-14 19:51:08.000000000 +0200
++++ busybox/archival/gzip.c    2005-06-04 08:20:08.000000000 +0200
+@@ -51,12 +51,6 @@
+ #include <time.h>
+ #include "busybox.h"
+-#define memzero(s, n)     memset ((void *)(s), 0, (n))
+-
+-#ifndef RETSIGTYPE
+-#  define RETSIGTYPE void
+-#endif
+-
+ typedef unsigned char uch;
+ typedef unsigned short ush;
+ typedef unsigned long ulg;
+@@ -214,9 +208,6 @@
+ static int zip(int in, int out);
+ static int file_read(char *buf, unsigned size);
+-      /* from gzip.c */
+-static RETSIGTYPE abort_gzip(void);
+-
+               /* from deflate.c */
+ static void lm_init(ush * flags);
+ static ulg deflate(void);
+@@ -335,7 +326,7 @@
+ /* ========================================================================
+  * Signal and error handler.
+  */
+-static void abort_gzip()
++static void abort_gzip(int ignored)
+ {
+       exit(ERROR);
+ }
+@@ -350,13 +341,6 @@
+       bytes_in = 0L;
+ }
+-static void write_bb_error_msg(void)
+-{
+-      fputc('\n', stderr);
+-      bb_perror_nomsg();
+-      abort_gzip();
+-}
+-
+ /* ===========================================================================
+  * Does the same as write(), but also handles partial pipe writes and checks
+  * for error return.
+@@ -366,9 +350,7 @@
+       unsigned n;
+       while ((n = write(fd, buf, cnt)) != cnt) {
+-              if (n == (unsigned) (-1)) {
+-                      write_bb_error_msg();
+-              }
++              if (n == (unsigned) (-1)) bb_error_msg_and_die("can't write");
+               cnt -= n;
+               buf = (void *) ((char *) buf + n);
+       }
+@@ -559,7 +541,7 @@
+ /* ===========================================================================
+  * Write out any remaining bits in an incomplete byte.
+  */
+-static void bi_windup()
++static void bi_windup(void)
+ {
+       if (bi_valid > 8) {
+               put_short(bi_buf);
+@@ -846,7 +828,7 @@
+       register unsigned j;
+       /* Initialize the hash table. */
+-      memzero((char *) head, HASH_SIZE * sizeof(*head));
++      memset(head, 0, HASH_SIZE * sizeof(*head));
+       /* prev will be initialized on the fly */
+       *flags |= SLOW;
+@@ -996,7 +978,7 @@
+  *    file reads are performed for at least two bytes (required for the
+  *    translate_eol option).
+  */
+-static void fill_window()
++static void fill_window(void)
+ {
+       register unsigned n, m;
+       unsigned more =
+@@ -1060,7 +1042,7 @@
+  * evaluation for matches: a match is finally adopted only if there is
+  * no better match at the next window position.
+  */
+-static ulg deflate()
++static ulg deflate(void)
+ {
+       IPos hash_head;         /* head of hash chain */
+       IPos prev_match;        /* previous match */
+@@ -1188,8 +1170,6 @@
+ typedef struct dirent dir_type;
+-typedef RETSIGTYPE(*sig_type) (int);
+-
+ /* ======================================================================== */
+ int gzip_main(int argc, char **argv)
+ {
+@@ -1235,16 +1215,16 @@
+       foreground = signal(SIGINT, SIG_IGN) != SIG_IGN;
+       if (foreground) {
+-              (void) signal(SIGINT, (sig_type) abort_gzip);
++              (void) signal(SIGINT, abort_gzip);
+       }
+ #ifdef SIGTERM
+       if (signal(SIGTERM, SIG_IGN) != SIG_IGN) {
+-              (void) signal(SIGTERM, (sig_type) abort_gzip);
++              (void) signal(SIGTERM, abort_gzip);
+       }
+ #endif
+ #ifdef SIGHUP
+       if (signal(SIGHUP, SIG_IGN) != SIG_IGN) {
+-              (void) signal(SIGHUP, (sig_type) abort_gzip);
++              (void) signal(SIGHUP, abort_gzip);
+       }
+ #endif
+@@ -1271,6 +1251,7 @@
+               for (i = optind; i < argc; i++) {
+                       char *path = NULL;
++                      clear_bufs();
+                       if (strcmp(argv[i], "-") == 0) {
+                               time_stamp = 0;
+                               ifile_size = -1L;
+@@ -1749,7 +1730,7 @@
+ /* ===========================================================================
+  * Initialize a new block.
+  */
+-static void init_block()
++static void init_block(void)
+ {
+       int n;                          /* iterates over tree elements */
+@@ -2162,7 +2143,7 @@
+  * Construct the Huffman tree for the bit lengths and return the index in
+  * bl_order of the last bit length code to send.
+  */
+-static const int build_bl_tree()
++static int build_bl_tree(void)
+ {
+       int max_blindex;        /* index of last bit length code of non zero freq */
+@@ -2425,7 +2406,7 @@
+  * IN assertion: the fields freq of dyn_ltree are set and the total of all
+  * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
+  */
+-static void set_file_type()
++static void set_file_type(void)
+ {
+       int n = 0;
+       unsigned ascii_freq = 0;
+@@ -2538,7 +2519,7 @@
+  * Write the output buffer outbuf[0..outcnt-1] and update bytes_out.
+  * (used for the compressed data only)
+  */
+-static void flush_outbuf()
++static void flush_outbuf(void)
+ {
+       if (outcnt == 0)
+               return;
+diff -Nur busybox-1.00/archival/libunarchive/archive_xread_all_eof.c busybox/archival/libunarchive/archive_xread_all_eof.c
+--- busybox-1.00/archival/libunarchive/archive_xread_all_eof.c 2003-11-21 23:24:48.000000000 +0100
++++ busybox/archival/libunarchive/archive_xread_all_eof.c      2005-06-04 08:20:08.000000000 +0200
+@@ -26,7 +26,7 @@
+       size = bb_full_read(archive_handle->src_fd, buf, count);
+       if ((size != 0) && (size != count)) {
+-              bb_perror_msg_and_die("Short read, read %d of %d", size, count);
++              bb_perror_msg_and_die("Short read, read %ld of %ld", (long)size, (long)count);
+       }
+       return(size);
+ }
+diff -Nur busybox-1.00/archival/libunarchive/check_header_gzip.c busybox/archival/libunarchive/check_header_gzip.c
+--- busybox-1.00/archival/libunarchive/check_header_gzip.c     2003-03-19 10:11:25.000000000 +0100
++++ busybox/archival/libunarchive/check_header_gzip.c  2005-06-04 08:20:08.000000000 +0200
+@@ -1,6 +1,7 @@
+ #include <stdlib.h>
+ #include <unistd.h>
+ #include "libbb.h"
++#include "unarchive.h" /* for external decl of check_header_gzip */
+ extern void check_header_gzip(int src_fd)
+ {
+diff -Nur busybox-1.00/archival/libunarchive/decompress_bunzip2.c busybox/archival/libunarchive/decompress_bunzip2.c
+--- busybox-1.00/archival/libunarchive/decompress_bunzip2.c    2004-08-28 02:43:05.000000000 +0200
++++ busybox/archival/libunarchive/decompress_bunzip2.c 2005-06-04 08:20:08.000000000 +0200
+@@ -134,8 +134,6 @@
+ static int get_next_block(bunzip_data *bd)
+ {
+-      /* Note: Ignore the warning about hufGroup, base and limit being used uninitialized.
+-       * They will be initialized on the fist pass of the loop. */
+       struct group_data *hufGroup;
+       int dbufCount,nextSym,dbufSize,groupCount,*base,*limit,selector,
+               i,j,k,t,runPos,symCount,symTotal,nSelectors,byteCount[256];
+@@ -286,16 +284,15 @@
+               mtfSymbol[i]=(unsigned char)i;
+       }
+       /* Loop through compressed symbols. */
+-      runPos=dbufCount=symCount=selector=0;
++      runPos=dbufCount=selector=0;
+       for(;;) {
+-              /* Determine which Huffman coding group to use. */
+-              if(!(symCount--)) {
+-                      symCount=GROUP_SIZE-1;
+-                      if(selector>=nSelectors) return RETVAL_DATA_ERROR;
+-                      hufGroup=bd->groups+selectors[selector++];
+-                      base=hufGroup->base-1;
+-                      limit=hufGroup->limit-1;
+-              }
++              /* fetch next Huffman coding group from list. */
++              symCount=GROUP_SIZE-1;
++              if(selector>=nSelectors) return RETVAL_DATA_ERROR;
++              hufGroup=bd->groups+selectors[selector++];
++              base=hufGroup->base-1;
++              limit=hufGroup->limit-1;
++continue_this_group:
+               /* Read next Huffman-coded symbol. */
+               /* Note: It is far cheaper to read maxLen bits and back up than it is
+                  to read minLen bits and then an additional bit at a time, testing
+@@ -346,7 +343,7 @@
+                          context).  Thus space is saved. */
+                       t += (runPos << nextSym); /* +runPos if RUNA; +2*runPos if RUNB */
+                       runPos <<= 1;
+-                      continue;
++                      goto end_of_huffman_loop;
+               }
+               /* When we hit the first non-run symbol after a run, we now know
+                  how many times to repeat the last literal, so append that many
+@@ -384,6 +381,10 @@
+               /* We have our literal byte.  Save it into dbuf. */
+               byteCount[uc]++;
+               dbuf[dbufCount++] = (unsigned int)uc;
++              /* Skip group initialization if we're not done with this group.  Done this
++               * way to avoid compiler warning. */
++end_of_huffman_loop:
++              if(symCount--) goto continue_this_group;
+       }
+       /* At this point, we've read all the Huffman-coded symbols (and repeated
+        runs) for this block from the input stream, and decoded them into the
+diff -Nur busybox-1.00/archival/libunarchive/decompress_uncompress.c busybox/archival/libunarchive/decompress_uncompress.c
+--- busybox-1.00/archival/libunarchive/decompress_uncompress.c 2004-04-14 19:51:08.000000000 +0200
++++ busybox/archival/libunarchive/decompress_uncompress.c      2005-06-04 08:20:08.000000000 +0200
+@@ -65,23 +65,23 @@
+ #define MAXCODE(n)    (1L << (n))
+ /* Block compress mode -C compatible with 2.0 */
+-int block_mode = BLOCK_MODE;
++static int block_mode = BLOCK_MODE;
+ /* user settable max # bits/code */
+-int maxbits = BITS;
++static int maxbits = BITS;
+ /* Exitcode of compress (-1 no file compressed) */
+-int exit_code = -1;
++static int exit_code = -1;
+ /* Input buffer */
+-unsigned char inbuf[IBUFSIZ + 64];
++static unsigned char inbuf[IBUFSIZ + 64];
+ /* Output buffer */
+-unsigned char outbuf[OBUFSIZ + 2048];
++static unsigned char outbuf[OBUFSIZ + 2048];
+-long int htab[HSIZE];
+-unsigned short codetab[HSIZE];
++static long int htab[HSIZE];
++static unsigned short codetab[HSIZE];
+ #define       htabof(i)                               htab[i]
+ #define       codetabof(i)                    codetab[i]
+diff -Nur busybox-1.00/archival/libunarchive/decompress_unzip.c busybox/archival/libunarchive/decompress_unzip.c
+--- busybox-1.00/archival/libunarchive/decompress_unzip.c      2004-04-25 07:11:13.000000000 +0200
++++ busybox/archival/libunarchive/decompress_unzip.c   2005-06-04 08:20:08.000000000 +0200
+@@ -151,7 +151,10 @@
+                       /* Leave the first 4 bytes empty so we can always unwind the bitbuffer
+                        * to the front of the bytebuffer, leave 4 bytes free at end of tail
+                        * so we can easily top up buffer in check_trailer_gzip() */
+-                      bytebuffer_size = 4 + bb_xread(gunzip_src_fd, &bytebuffer[4], bytebuffer_max - 8);
++                      if (!(bytebuffer_size = bb_xread(gunzip_src_fd, &bytebuffer[4], bytebuffer_max - 8))) {
++                              bb_error_msg_and_die("unexpected end of file");
++                      }
++                      bytebuffer_size += 4;
+                       bytebuffer_offset = 4;
+               }
+               bitbuffer |= ((unsigned int) bytebuffer[bytebuffer_offset]) << *current;
+diff -Nur busybox-1.00/archival/rpm.c busybox/archival/rpm.c
+--- busybox-1.00/archival/rpm.c        2004-03-15 09:28:16.000000000 +0100
++++ busybox/archival/rpm.c     2005-06-04 08:20:08.000000000 +0200
+@@ -260,12 +260,16 @@
+ int bsearch_rpmtag(const void *key, const void *item)
+ {
+       rpm_index **tmp = (rpm_index **) item;
++      /* gcc throws warnings here when sizeof(void*)!=sizeof(int) ...
++       * it's ok to ignore it because this isn't a 'real' pointer */
+       return ((int) key - tmp[0]->tag);
+ }
+ int rpm_getcount(int tag)
+ {
+       rpm_index **found;
++      /* gcc throws warnings here when sizeof(void*)!=sizeof(int) ...
++       * it's ok to ignore it because tag won't be used as a pointer */
+       found = bsearch((void *) tag, mytags, tagcount, sizeof(struct rpmtag *), bsearch_rpmtag);
+       if (!found) return 0;
+       else return found[0]->count;
+@@ -274,6 +278,8 @@
+ char *rpm_getstring(int tag, int itemindex)
+ {
+       rpm_index **found;
++      /* gcc throws warnings here when sizeof(void*)!=sizeof(int) ...
++       * it's ok to ignore it because tag won't be used as a pointer */
+       found = bsearch((void *) tag, mytags, tagcount, sizeof(struct rpmtag *), bsearch_rpmtag);
+       if (!found || itemindex >= found[0]->count) return NULL;
+       if (found[0]->type == RPM_STRING_TYPE || found[0]->type == RPM_I18NSTRING_TYPE || found[0]->type == RPM_STRING_ARRAY_TYPE) {
+@@ -288,6 +294,8 @@
+ {
+       rpm_index **found;
+       int n, *tmpint;
++      /* gcc throws warnings here when sizeof(void*)!=sizeof(int) ...
++       * it's ok to ignore it because tag won't be used as a pointer */
+       found = bsearch((void *) tag, mytags, tagcount, sizeof(struct rpmtag *), bsearch_rpmtag);
+       if (!found || itemindex >= found[0]->count) return -1;
+       tmpint = (int *) (map + found[0]->offset);
+diff -Nur busybox-1.00/archival/rpm2cpio.c busybox/archival/rpm2cpio.c
+--- busybox-1.00/archival/rpm2cpio.c   2004-03-27 11:02:41.000000000 +0100
++++ busybox/archival/rpm2cpio.c        2005-06-04 08:20:08.000000000 +0200
+@@ -48,7 +48,7 @@
+       uint32_t size; /* Size of store (4 bytes) */
+ };
+-void skip_header(int rpm_fd)
++static void skip_header(int rpm_fd)
+ {
+       struct rpm_header header;
+diff -Nur busybox-1.00/archival/tar.c busybox/archival/tar.c
+--- busybox-1.00/archival/tar.c        2004-08-27 00:18:56.000000000 +0200
++++ busybox/archival/tar.c     2005-06-04 08:20:08.000000000 +0200
+@@ -724,7 +724,7 @@
+                               );
+       /* Check one and only one context option was given */
+-      if(opt & 0x80000000UL) {
++      if(opt & BB_GETOPT_ERROR) {
+               bb_show_usage();
+       }
+ #ifdef CONFIG_FEATURE_TAR_CREATE
+diff -Nur busybox-1.00/coreutils/Config.in busybox/coreutils/Config.in
+--- busybox-1.00/coreutils/Config.in   2004-08-11 04:45:47.000000000 +0200
++++ busybox/coreutils/Config.in        2005-06-04 08:20:13.000000000 +0200
+@@ -59,6 +59,13 @@
+         cmp is used to compare two files and returns the result
+         to standard output.
++config CONFIG_COMM
++      bool "comm"
++      default n
++      help
++        comm is used to compare two files line by line and return
++        a three-column output.
++
+ config CONFIG_CP
+       bool "cp"
+       default n
+@@ -164,6 +171,12 @@
+         a command; without options it displays the current
+         environment.
++config CONFIG_PRINTENV
++      bool "printenv"
++      default n
++      help
++        printenv is used to print all or part of environment.
++
+ config CONFIG_EXPR
+       bool "expr"
+       default n
+@@ -329,6 +342,12 @@
+       help
+         mv is used to move or rename files or directories.
++config CONFIG_NICE
++      bool "nice"
++      default n
++      help
++        nice runs a program with modified scheduling priority.
++
+ config CONFIG_OD
+       bool "od"
+       default n
+@@ -398,12 +417,45 @@
+       help
+         sort is used to sort lines of text in specified files.
++config CONFIG_SORT_BIG
++      bool "  full SuSv3 compliant sort (Support -ktcsbdfiozgM)"
++      default y
++      depends on CONFIG_SORT
++      help
++        Without this, sort only supports  -r, -u, and an integer version
++        of -n.  Selecting this adds sort keys, floating point support, and
++        more.  This adds a little over 3k to a nonstatic build on x86.
++
++        The SuSv3 sort standard is available at:
++        http://www.opengroup.org/onlinepubs/007904975/utilities/sort.html
++
++config CONFIG_STAT
++      bool "stat"
++      default n
++      help
++        display file or filesystem status.
++
++config CONFIG_FEATURE_STAT_FORMAT
++      bool "  Enable custom formats (-c)"
++      default n
++      depends on CONFIG_STAT
++      help
++        Without this, stat will not support the '-c format' option where 
++        users can pass a custom format string for output.  This adds about 
++        7k to a nonstatic build on amd64.
++
+ config CONFIG_STTY
+       bool "stty"
+       default n
+       help
+         stty is used to change and print terminal line settings.
++config CONFIG_SUM
++      bool "sum"
++      default n
++      help
++        checksum and count the blocks in a file
++
+ config CONFIG_SYNC
+       bool "sync"
+       default n
+diff -Nur busybox-1.00/coreutils/Makefile.in busybox/coreutils/Makefile.in
+--- busybox-1.00/coreutils/Makefile.in 2004-10-08 09:45:14.000000000 +0200
++++ busybox/coreutils/Makefile.in      2005-06-04 08:20:13.000000000 +0200
+@@ -24,69 +24,74 @@
+ srcdir=$(top_srcdir)/coreutils
+ COREUTILS-y:=
+-COREUTILS-$(CONFIG_BASENAME)  += basename.o
+-COREUTILS-$(CONFIG_CAL)       += cal.o
+-COREUTILS-$(CONFIG_CAT)       += cat.o
+-COREUTILS-$(CONFIG_CHGRP)     += chgrp.o
+-COREUTILS-$(CONFIG_CHMOD)     += chmod.o
+-COREUTILS-$(CONFIG_CHOWN)     += chown.o
+-COREUTILS-$(CONFIG_CHROOT)    += chroot.o
+-COREUTILS-$(CONFIG_CMP)       += cmp.o
+-COREUTILS-$(CONFIG_CP)        += cp.o
+-COREUTILS-$(CONFIG_CUT)       += cut.o
+-COREUTILS-$(CONFIG_DATE)      += date.o
+-COREUTILS-$(CONFIG_DD)        += dd.o
+-COREUTILS-$(CONFIG_DF)        += df.o
+-COREUTILS-$(CONFIG_DIRNAME)   += dirname.o
+-COREUTILS-$(CONFIG_DOS2UNIX)  += dos2unix.o
+-COREUTILS-$(CONFIG_DU)        += du.o
+-COREUTILS-$(CONFIG_ECHO)      += echo.o
+-COREUTILS-$(CONFIG_ENV)       += env.o
+-COREUTILS-$(CONFIG_EXPR)      += expr.o
+-COREUTILS-$(CONFIG_FALSE)     += false.o
+-COREUTILS-$(CONFIG_FOLD)      += fold.o
+-COREUTILS-$(CONFIG_HEAD)      += head.o
+-COREUTILS-$(CONFIG_HOSTID)    += hostid.o
+-COREUTILS-$(CONFIG_ID)        += id.o
+-COREUTILS-$(CONFIG_INSTALL)   += install.o
+-COREUTILS-$(CONFIG_LENGTH)    += length.o
+-COREUTILS-$(CONFIG_LN)        += ln.o
+-COREUTILS-$(CONFIG_LOGNAME)   += logname.o
+-COREUTILS-$(CONFIG_LS)        += ls.o
+-COREUTILS-$(CONFIG_MD5SUM)    += md5_sha1_sum.o
+-COREUTILS-$(CONFIG_MKDIR)     += mkdir.o
+-COREUTILS-$(CONFIG_MKFIFO)    += mkfifo.o
+-COREUTILS-$(CONFIG_MKNOD)     += mknod.o
+-COREUTILS-$(CONFIG_MV)        += mv.o
+-COREUTILS-$(CONFIG_OD)        += od.o
+-COREUTILS-$(CONFIG_PRINTF)    += printf.o
+-COREUTILS-$(CONFIG_PWD)       += pwd.o
+-COREUTILS-$(CONFIG_REALPATH)  += realpath.o
+-COREUTILS-$(CONFIG_RM)        += rm.o
+-COREUTILS-$(CONFIG_RMDIR)     += rmdir.o
+-COREUTILS-$(CONFIG_SEQ)       += seq.o
+-COREUTILS-$(CONFIG_SHA1SUM)   += md5_sha1_sum.o
+-COREUTILS-$(CONFIG_SLEEP)     += sleep.o
+-COREUTILS-$(CONFIG_SORT)      += sort.o
+-COREUTILS-$(CONFIG_STTY)      += stty.o
+-COREUTILS-$(CONFIG_SYNC)      += sync.o
+-COREUTILS-$(CONFIG_TAIL)      += tail.o
+-COREUTILS-$(CONFIG_TEE)       += tee.o
+-COREUTILS-$(CONFIG_TEST)      += test.o
+-COREUTILS-$(CONFIG_TOUCH)     += touch.o
+-COREUTILS-$(CONFIG_TR)        += tr.o
+-COREUTILS-$(CONFIG_TRUE)      += true.o
+-COREUTILS-$(CONFIG_TTY)       += tty.o
+-COREUTILS-$(CONFIG_UNAME)     += uname.o
+-COREUTILS-$(CONFIG_UNIQ)      += uniq.o
+-COREUTILS-$(CONFIG_USLEEP)    += usleep.o
+-COREUTILS-$(CONFIG_UUDECODE)  += uudecode.o
+-COREUTILS-$(CONFIG_UUENCODE)  += uuencode.o
+-COREUTILS-$(CONFIG_WATCH)     += watch.o
+-COREUTILS-$(CONFIG_WC)        += wc.o
+-COREUTILS-$(CONFIG_WHO)       += who.o
+-COREUTILS-$(CONFIG_WHOAMI)    += whoami.o
+-COREUTILS-$(CONFIG_YES)       += yes.o
++COREUTILS-$(CONFIG_BASENAME)  += basename.o
++COREUTILS-$(CONFIG_CAL)       += cal.o
++COREUTILS-$(CONFIG_CAT)       += cat.o
++COREUTILS-$(CONFIG_CHGRP)     += chgrp.o
++COREUTILS-$(CONFIG_CHMOD)     += chmod.o
++COREUTILS-$(CONFIG_CHOWN)     += chown.o
++COREUTILS-$(CONFIG_CHROOT)    += chroot.o
++COREUTILS-$(CONFIG_CMP)       += cmp.o
++COREUTILS-$(CONFIG_COMM)      += comm.o
++COREUTILS-$(CONFIG_CP)        += cp.o
++COREUTILS-$(CONFIG_CUT)       += cut.o
++COREUTILS-$(CONFIG_DATE)      += date.o
++COREUTILS-$(CONFIG_DD)        += dd.o
++COREUTILS-$(CONFIG_DF)        += df.o
++COREUTILS-$(CONFIG_DIRNAME)   += dirname.o
++COREUTILS-$(CONFIG_DOS2UNIX)  += dos2unix.o
++COREUTILS-$(CONFIG_DU)        += du.o
++COREUTILS-$(CONFIG_ECHO)      += echo.o
++COREUTILS-$(CONFIG_ENV)       += env.o
++COREUTILS-$(CONFIG_EXPR)      += expr.o
++COREUTILS-$(CONFIG_FALSE)     += false.o
++COREUTILS-$(CONFIG_FOLD)      += fold.o
++COREUTILS-$(CONFIG_HEAD)      += head.o
++COREUTILS-$(CONFIG_HOSTID)    += hostid.o
++COREUTILS-$(CONFIG_ID)        += id.o
++COREUTILS-$(CONFIG_INSTALL)   += install.o
++COREUTILS-$(CONFIG_LENGTH)    += length.o
++COREUTILS-$(CONFIG_LN)        += ln.o
++COREUTILS-$(CONFIG_LOGNAME)   += logname.o
++COREUTILS-$(CONFIG_LS)        += ls.o
++COREUTILS-$(CONFIG_MD5SUM)    += md5_sha1_sum.o
++COREUTILS-$(CONFIG_MKDIR)     += mkdir.o
++COREUTILS-$(CONFIG_MKFIFO)    += mkfifo.o
++COREUTILS-$(CONFIG_MKNOD)     += mknod.o
++COREUTILS-$(CONFIG_MV)        += mv.o
++COREUTILS-$(CONFIG_NICE)      += nice.o
++COREUTILS-$(CONFIG_OD)        += od.o
++COREUTILS-$(CONFIG_PRINTENV)  += printenv.o
++COREUTILS-$(CONFIG_PRINTF)    += printf.o
++COREUTILS-$(CONFIG_PWD)       += pwd.o
++COREUTILS-$(CONFIG_REALPATH)  += realpath.o
++COREUTILS-$(CONFIG_RM)        += rm.o
++COREUTILS-$(CONFIG_RMDIR)     += rmdir.o
++COREUTILS-$(CONFIG_SEQ)       += seq.o
++COREUTILS-$(CONFIG_SHA1SUM)   += md5_sha1_sum.o
++COREUTILS-$(CONFIG_SLEEP)     += sleep.o
++COREUTILS-$(CONFIG_SORT)      += sort.o
++COREUTILS-$(CONFIG_STAT)      += stat.o
++COREUTILS-$(CONFIG_STTY)      += stty.o
++COREUTILS-$(CONFIG_SUM)       += sum.o
++COREUTILS-$(CONFIG_SYNC)      += sync.o
++COREUTILS-$(CONFIG_TAIL)      += tail.o
++COREUTILS-$(CONFIG_TEE)       += tee.o
++COREUTILS-$(CONFIG_TEST)      += test.o
++COREUTILS-$(CONFIG_TOUCH)     += touch.o
++COREUTILS-$(CONFIG_TR)        += tr.o
++COREUTILS-$(CONFIG_TRUE)      += true.o
++COREUTILS-$(CONFIG_TTY)       += tty.o
++COREUTILS-$(CONFIG_UNAME)     += uname.o
++COREUTILS-$(CONFIG_UNIQ)      += uniq.o
++COREUTILS-$(CONFIG_USLEEP)    += usleep.o
++COREUTILS-$(CONFIG_UUDECODE)  += uudecode.o
++COREUTILS-$(CONFIG_UUENCODE)  += uuencode.o
++COREUTILS-$(CONFIG_WATCH)     += watch.o
++COREUTILS-$(CONFIG_WC)        += wc.o
++COREUTILS-$(CONFIG_WHO)       += who.o
++COREUTILS-$(CONFIG_WHOAMI)    += whoami.o
++COREUTILS-$(CONFIG_YES)       += yes.o
+ libraries-y+=$(COREUTILS_DIR)$(COREUTILS_AR)
+@@ -95,4 +100,3 @@
+ $(COREUTILS_DIR)%.o: $(srcdir)/%.c
+       $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
+-
+diff -Nur busybox-1.00/coreutils/comm.c busybox/coreutils/comm.c
+--- busybox-1.00/coreutils/comm.c      1970-01-01 01:00:00.000000000 +0100
++++ busybox/coreutils/comm.c   2005-06-04 08:20:13.000000000 +0200
+@@ -0,0 +1,144 @@
++/* vi: set sw=4 ts=4: */
++/*
++ * Mini comm implementation for busybox
++ *
++ * Copyright (C) 2005 by Robert Sullivan <cogito.ergo.cogito@gmail.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ * 02111-1307 USA
++ *
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <unistd.h>
++#include "busybox.h"
++
++#define COMM_OPT_1 0x01
++#define COMM_OPT_2 0x02
++#define COMM_OPT_3 0x04
++
++/* These three variables control behaviour if non-zero */
++
++static int only_file_1;
++static int only_file_2;
++static int both;
++
++/* writeline outputs the input given, appropriately aligned according to class */
++static void writeline(char *line, int class)
++{
++      if (class == 0) {
++              if (!only_file_1)
++                      return;
++      } else if (class == 1) {
++              if (!only_file_2)
++                      return;
++              if (only_file_1)
++                      putchar('\t');
++      }
++      else /*if (class == 2)*/ {
++              if (!both)
++                      return;
++              if (only_file_1)
++                      putchar('\t');
++              if (only_file_2)
++                      putchar('\t');
++      }
++      fputs(line, stdout);
++}
++
++/* This is the real core of the program - lines are compared here */
++static void cmp_files(char **infiles)
++{
++#define LINE_LEN 100
++#define BB_EOF_0 0x1
++#define BB_EOF_1 0x2
++      char thisline[2][LINE_LEN];
++      FILE *streams[2];
++      int i;
++
++      for (i = 0; i < 2; ++i) {
++              streams[i] = ((infiles[i][0] == '=' && infiles[i][1]) ? stdin : bb_xfopen(infiles[i], "r"));
++              fgets(thisline[i], LINE_LEN, streams[i]);
++      }
++
++      while (thisline[0] || thisline[1]) {
++              int order = 0;
++
++              i = 0;
++              if (feof(streams[0])) i |= BB_EOF_0;
++              if (feof(streams[1])) i |= BB_EOF_1;
++
++              if (!thisline[0])
++                      order = 1;
++              else if (!thisline[1])
++                      order = -1;
++              else {
++                      int tl0_len, tl1_len;
++                      tl0_len = strlen(thisline[0]);
++                      tl1_len = strlen(thisline[1]);
++                      order = memcmp(thisline[0], thisline[1], tl0_len < tl1_len ? tl0_len : tl1_len);
++                      if (!order)
++                              order = tl0_len < tl1_len ? -1 : tl0_len != tl1_len;
++              }
++
++              if (order == 0 && !i)
++                      writeline(thisline[1], 2);
++              else if (order > 0 && !(i & BB_EOF_1))
++                      writeline(thisline[1], 1);
++              else if (order < 0 && !(i & BB_EOF_0))
++                      writeline(thisline[0], 0);
++
++              if (i & BB_EOF_0 & BB_EOF_1) {
++                      break;
++
++              } else if (i) {
++                      i = (i & BB_EOF_0 ? 1 : 0);
++                      while (!feof(streams[i])) {
++                              if ((order < 0 && i) || (order > 0 && !i))
++                                      writeline(thisline[i], i);
++                              fgets(thisline[i], LINE_LEN, streams[i]);
++                      }
++                      break;
++
++              } else {
++                      if (order >= 0)
++                              fgets(thisline[1], LINE_LEN, streams[1]);
++                      if (order <= 0)
++                              fgets(thisline[0], LINE_LEN, streams[0]);
++              }
++      }
++
++      fclose(streams[0]);
++      fclose(streams[1]);
++}
++
++int comm_main(int argc, char **argv)
++{
++      unsigned long flags;
++
++      flags = bb_getopt_ulflags(argc, argv, "123");
++
++      if (optind + 2 != argc)
++              bb_show_usage();
++
++      only_file_1 = !(flags & COMM_OPT_1);
++      only_file_2 = !(flags & COMM_OPT_2);
++      both = !(flags & COMM_OPT_3);
++
++      cmp_files(argv + optind);
++      exit(EXIT_SUCCESS);
++}
+diff -Nur busybox-1.00/coreutils/cp.c busybox/coreutils/cp.c
+--- busybox-1.00/coreutils/cp.c        2004-01-25 06:50:28.000000000 +0100
++++ busybox/coreutils/cp.c     2005-06-04 08:20:13.000000000 +0200
+@@ -42,7 +42,7 @@
+ #include "libcoreutils/coreutils.h"
+ /* WARNING!! ORDER IS IMPORTANT!! */
+-static const char cp_opts[] = "pdRfiar";
++static const char cp_opts[] = "pdRfiarPHL";
+ extern int cp_main(int argc, char **argv)
+ {
+@@ -70,9 +70,23 @@
+       if (flags & 64) {
+               /* Make -r a synonym for -R,
+                * -r was marked as obsolete in SUSv3, but is included for compatability
+-               */
++               */
+               flags |= FILEUTILS_RECUR;
+       }
++      if (flags & 128) {
++              /* Make -P a synonym for -d,
++               * -d is the GNU option while -P is the POSIX 2003 option
++               */
++              flags |= FILEUTILS_DEREFERENCE;
++      }
++      /* Default behavior of cp is to dereference, so we don't have to do
++       * anything special when we are given -L.
++       * The behavior of -H is *almost* like -L, but not quite, so let's
++       * just ignore it too for fun.
++      if (flags & 256 || flags & 512) {
++              ;
++      }
++      */
+       flags ^= FILEUTILS_DEREFERENCE;         /* The sense of this flag was reversed. */
+@@ -86,7 +100,7 @@
+       /* If there are only two arguments and...  */
+       if (optind + 2 == argc) {
+               s_flags = cp_mv_stat2(*argv, &source_stat,
+-                                                               (flags & FILEUTILS_DEREFERENCE) ? stat : lstat);
++                                    (flags & FILEUTILS_DEREFERENCE) ? stat : lstat);
+               if ((s_flags < 0) || ((d_flags = cp_mv_stat(last, &dest_stat)) < 0)) {
+                       exit(EXIT_FAILURE);
+               }
+@@ -98,8 +112,8 @@
+                       ((((flags & FILEUTILS_RECUR) >> 1) & s_flags) && !d_flags)
+               ) {
+                       /* ...do a simple copy.  */
+-                              dest = last;
+-                              goto DO_COPY; /* Note: optind+2==argc implies argv[1]==last below. */
++                      dest = last;
++                      goto DO_COPY; /* Note: optind+2==argc implies argv[1]==last below. */
+               }
+       }
+diff -Nur busybox-1.00/coreutils/cut.c busybox/coreutils/cut.c
+--- busybox-1.00/coreutils/cut.c       2004-04-14 19:51:09.000000000 +0200
++++ busybox/coreutils/cut.c    2005-06-04 08:20:13.000000000 +0200
+@@ -300,7 +300,7 @@
+       part = opt & (OPT_BYTE_FLGS|OPT_CHAR_FLGS|OPT_FIELDS_FLGS);
+       if(part == 0)
+               bb_error_msg_and_die("you must specify a list of bytes, characters, or fields");
+-      if(opt & 0x80000000UL)
++      if(opt & BB_GETOPT_ERROR)
+               bb_error_msg_and_die("only one type of list may be specified");
+       parse_lists(sopt);
+       if((opt & (OPT_DELIM_FLGS))) {
+diff -Nur busybox-1.00/coreutils/date.c busybox/coreutils/date.c
+--- busybox-1.00/coreutils/date.c      2004-10-11 22:52:16.000000000 +0200
++++ busybox/coreutils/date.c   2005-06-04 08:20:13.000000000 +0200
+@@ -136,7 +136,6 @@
+ {
+       char *date_str = NULL;
+       char *date_fmt = NULL;
+-      char *t_buff;
+       int set_time;
+       int utc;
+       int use_arg = 0;
+@@ -166,7 +165,7 @@
+               bb_error_msg_and_die(bb_msg_memory_exhausted);
+       }
+       use_arg = opt & DATE_OPT_DATE;
+-      if(opt & 0x80000000UL)
++      if(opt & BB_GETOPT_ERROR)
+               bb_show_usage();
+ #ifdef CONFIG_FEATURE_DATE_ISOFMT
+       if(opt & DATE_OPT_TIMESPEC) {
+@@ -283,10 +282,13 @@
+               date_fmt = "%Y.%m.%d-%H:%M:%S";
+       }
+-      /* Print OUTPUT (after ALL that!) */
+-      t_buff = xmalloc(201);
+-      strftime(t_buff, 200, date_fmt, &tm_time);
+-      puts(t_buff);
++      {
++              /* Print OUTPUT (after ALL that!) */
++              RESERVE_CONFIG_BUFFER(t_buff, 201);
++              strftime(t_buff, 200, date_fmt, &tm_time);
++              puts(t_buff);
++              RELEASE_CONFIG_BUFFER(t_buff);
++      }
+       return EXIT_SUCCESS;
+ }
+diff -Nur busybox-1.00/coreutils/expr.c busybox/coreutils/expr.c
+--- busybox-1.00/coreutils/expr.c      2004-04-14 19:51:09.000000000 +0200
++++ busybox/coreutils/expr.c   2005-06-04 08:20:13.000000000 +0200
+@@ -245,10 +245,9 @@
+ static VALUE *docolon (VALUE *sv, VALUE *pv)
+ {
+       VALUE *v;
+-      const char *errmsg;
+-      struct re_pattern_buffer re_buffer;
+-      struct re_registers re_regs;
+-      int len;
++      regex_t re_buffer;
++      const int NMATCH = 2;
++      regmatch_t re_regs[NMATCH];
+       tostring (sv);
+       tostring (pv);
+@@ -260,27 +259,22 @@
+               pv->u.s);
+       }
+-      len = strlen (pv->u.s);
+       memset (&re_buffer, 0, sizeof (re_buffer));
+-      memset (&re_regs, 0, sizeof (re_regs));
+-      re_buffer.allocated = 2 * len;
+-      re_buffer.buffer = (unsigned char *) xmalloc (re_buffer.allocated);
+-      re_buffer.translate = 0;
+-      re_syntax_options = RE_SYNTAX_POSIX_BASIC;
+-      errmsg = re_compile_pattern (pv->u.s, len, &re_buffer);
+-      if (errmsg) {
+-              bb_error_msg_and_die("%s", errmsg);
+-      }
+-
+-      len = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);
+-      if (len >= 0) {
++      memset (re_regs, 0, sizeof (*re_regs));
++      if( regcomp (&re_buffer, pv->u.s, 0) != 0 )
++              bb_error_msg_and_die("Invalid regular expression");
++
++      /* expr uses an anchored pattern match, so check that there was a
++       * match and that the match starts at offset 0. */
++      if (regexec (&re_buffer, sv->u.s, NMATCH, re_regs, 0) != REG_NOMATCH &&
++                      re_regs[0].rm_so == 0) {
+               /* Were \(...\) used? */
+-              if (re_buffer.re_nsub > 0) { /* was (re_regs.start[1] >= 0) */
+-                      sv->u.s[re_regs.end[1]] = '\0';
+-                      v = str_value (sv->u.s + re_regs.start[1]);
++              if (re_buffer.re_nsub > 0) {
++                      sv->u.s[re_regs[1].rm_eo] = '\0';
++                      v = str_value (sv->u.s + re_regs[1].rm_so);
+               }
+               else
+-                      v = int_value (len);
++                      v = int_value (re_regs[0].rm_eo);
+       }
+       else {
+               /* Match failed -- return the right kind of null.  */
+@@ -289,7 +283,6 @@
+               else
+                       v = int_value (0);
+       }
+-      free (re_buffer.buffer);
+       return v;
+ }
+diff -Nur busybox-1.00/coreutils/id.c busybox/coreutils/id.c
+--- busybox-1.00/coreutils/id.c        2004-09-15 05:04:07.000000000 +0200
++++ busybox/coreutils/id.c     2005-06-04 08:20:13.000000000 +0200
+@@ -32,8 +32,7 @@
+ #include <sys/types.h>
+ #ifdef CONFIG_SELINUX
+-#include <proc_secure.h>
+-#include <flask_util.h>
++#include <selinux/selinux.h>          /* for is_selinux_enabled() */
+ #endif
+ #define PRINT_REAL        1
+@@ -61,14 +60,11 @@
+       gid_t gid;
+       unsigned long flags;
+       short status;
+-#ifdef CONFIG_SELINUX
+-      int is_flask_enabled_flag = is_flask_enabled();
+-#endif
+       bb_opt_complementaly = "u~g:g~u";
+       flags = bb_getopt_ulflags(argc, argv, "rnug");
+-      if ((flags & 0x80000000UL)
++      if ((flags & BB_GETOPT_ERROR)
+       /* Don't allow -n -r -nr */
+       || (flags <= 3 && flags > 0) 
+       /* Don't allow more than one username */
+@@ -109,17 +105,26 @@
+       putchar(' ');
+       /* my_getgrgid doesn't exit on failure here */
+       status|=printf_full(gid, my_getgrgid(NULL, gid, 0), 'g');
++
+ #ifdef CONFIG_SELINUX
+-      if(is_flask_enabled_flag) {
+-              security_id_t mysid = getsecsid();
+-              char context[80];
+-              int len = sizeof(context);
+-              context[0] = '\0';
+-              if(security_sid_to_context(mysid, context, &len))
+-                      strcpy(context, "unknown");
++      if ( is_selinux_enabled() ) {
++                      security_context_t mysid;
++                      char context[80];
++                      int len = sizeof(context);
++
++                      getcon(&mysid);
++                      context[0] = '\0';
++                      if (mysid) {
++                                      len = strlen(mysid)+1;
++                                      safe_strncpy(context, mysid, len);
++                                      freecon(mysid);
++                      }else{
++                                      safe_strncpy(context, "unknown",8);
++                      }
+               bb_printf(" context=%s", context);
+       }
+ #endif
++
+       putchar('\n');
+       bb_fflush_stdout_and_exit(status);
+ }
+diff -Nur busybox-1.00/coreutils/install.c busybox/coreutils/install.c
+--- busybox-1.00/coreutils/install.c   2004-04-25 07:11:14.000000000 +0200
++++ busybox/coreutils/install.c        2005-06-04 08:20:13.000000000 +0200
+@@ -69,7 +69,7 @@
+       flags = bb_getopt_ulflags(argc, argv, "cdpsg:m:o:", &gid_str, &mode_str, &uid_str);     /* 'a' must be 2nd */
+       /* Check valid options were given */
+-      if(flags & 0x80000000UL) {
++      if(flags & BB_GETOPT_ERROR) {
+               bb_show_usage();
+       }
+diff -Nur busybox-1.00/coreutils/ln.c busybox/coreutils/ln.c
+--- busybox-1.00/coreutils/ln.c        2004-03-15 09:28:20.000000000 +0100
++++ busybox/coreutils/ln.c     2005-06-04 08:20:13.000000000 +0200
+@@ -21,21 +21,20 @@
+  */
+ /* BB_AUDIT SUSv3 compliant */
+-/* BB_AUDIT GNU options missing: -b, -d, -F, -i, -S, and -v. */
++/* BB_AUDIT GNU options missing: -d, -F, -i, and -v. */
+ /* http://www.opengroup.org/onlinepubs/007904975/utilities/ln.html */
+-/* Mar 16, 2003      Manuel Novoa III   (mjn3@codepoet.org)
+- *
+- * Fixed bug involving -n option.  Essentially, -n was always in effect.
+- */
+-
++#include <stdio.h>
+ #include <stdlib.h>
+ #include <unistd.h>
++#include <errno.h>
+ #include "busybox.h"
+ #define LN_SYMLINK          1
+ #define LN_FORCE            2
+ #define LN_NODEREFERENCE    4
++#define LN_BACKUP           8
++#define LN_SUFFIX           16
+ extern int ln_main(int argc, char **argv)
+ {
+@@ -44,10 +43,11 @@
+       char *last;
+       char *src_name;
+       char *src;
++      char *suffix = "~";
+       struct stat statbuf;
+       int (*link_func)(const char *, const char *);
+-      flag = bb_getopt_ulflags(argc, argv, "sfn");
++      flag = bb_getopt_ulflags(argc, argv, "sfnbS:", &suffix);
+       if (argc == optind) {
+               bb_show_usage();
+@@ -80,7 +80,23 @@
+                       continue;
+               }
+-              if (flag & LN_FORCE) {
++              if (flag & LN_BACKUP) {
++                              char *backup = NULL;
++                              bb_xasprintf(&backup, "%s%s", src, suffix);
++                              if (rename(src, backup) < 0 && errno != ENOENT) {
++                                              bb_perror_msg(src);
++                                              status = EXIT_FAILURE;
++                                              free(backup);
++                                              continue;
++                              }
++                              free(backup);
++                              /*
++                               * When the source and dest are both hard links to the same
++                               * inode, a rename may succeed even though nothing happened.
++                               * Therefore, always unlink().
++                               */
++                              unlink(src);
++              } else if (flag & LN_FORCE) {
+                       unlink(src);
+               }
+diff -Nur busybox-1.00/coreutils/ls.c busybox/coreutils/ls.c
+--- busybox-1.00/coreutils/ls.c        2004-09-24 04:04:13.000000000 +0200
++++ busybox/coreutils/ls.c     2005-06-04 08:20:13.000000000 +0200
+@@ -64,9 +64,7 @@
+ #include <sys/sysmacros.h>     /* major() and minor() */
+ #include "busybox.h"
+ #ifdef CONFIG_SELINUX
+-#include <fs_secure.h>
+-#include <flask_util.h>
+-#include <ss.h>
++#include <selinux/selinux.h>   /* for is_selinux_enabled() */
+ #endif
+ #ifdef CONFIG_FEATURE_LS_TIMESTAMPS
+@@ -182,7 +180,7 @@
+       char *fullname;         /* the dir entry name */
+       struct stat dstat;      /* the file stat info */
+ #ifdef CONFIG_SELINUX
+-      security_id_t sid;
++      security_context_t sid;
+ #endif
+       struct dnode *next;     /* point at the next node */
+ };
+@@ -195,7 +193,7 @@
+ static unsigned int all_fmt;
+ #ifdef CONFIG_SELINUX
+-static int is_flask_enabled_flag;
++static int selinux_enabled= 0;
+ #endif
+ #ifdef CONFIG_FEATURE_AUTOWIDTH
+@@ -213,18 +211,19 @@
+       struct stat dstat;
+       struct dnode *cur;
+ #ifdef CONFIG_SELINUX
+-      security_id_t sid;
++      security_context_t sid=NULL;
+ #endif
+       int rc;
+ #ifdef CONFIG_FEATURE_LS_FOLLOWLINKS
+       if (all_fmt & FOLLOW_LINKS) {
+ #ifdef CONFIG_SELINUX
+-              if(is_flask_enabled_flag)
+-                      rc = stat_secure(fullname, &dstat, &sid);
+-              else
++              if (is_selinux_enabled())  {
++                rc=0; /*  Set the number which means success before hand.  */
++                rc = getfilecon(fullname,&sid);
++              }
+ #endif
+-                      rc = stat(fullname, &dstat);
++                rc = stat(fullname, &dstat);
+               if(rc)
+               {
+                       bb_perror_msg("%s", fullname);
+@@ -235,11 +234,12 @@
+ #endif
+       {
+ #ifdef CONFIG_SELINUX
+-              if(is_flask_enabled_flag)
+-                      rc = lstat_secure(fullname, &dstat, &sid);
+-              else
++              if  (is_selinux_enabled())  {
++                rc=0; /*  Set the number which means success before hand.  */
++                rc = lgetfilecon(fullname,&sid);
++              }
+ #endif
+-                      rc = lstat(fullname, &dstat);
++              rc = lstat(fullname, &dstat);
+               if(rc)
+               {
+                       bb_perror_msg("%s", fullname);
+@@ -736,12 +736,16 @@
+ #ifdef CONFIG_SELINUX
+               case LIST_CONTEXT:
+                       {
+-                              char context[64];
+-                              int len = sizeof(context);
+-                              if(security_sid_to_context(dn->sid, context, &len))
+-                              {
+-                                      strcpy(context, "unknown");
+-                                      len = 7;
++                              char context[80];
++                              int len;
++                      
++                              if (dn->sid) {
++                                /*  I assume sid initilized with NULL  */
++                                len = strlen(dn->sid)+1;
++                                safe_strncpy(context, dn->sid, len);
++                                freecon(dn->sid);
++                              }else {
++                                safe_strncpy(context, "unknown",8);
+                               }
+                               printf("%-32s ", context);
+                               column += MAX(33, len);
+@@ -963,10 +967,6 @@
+       char *terminal_width_str = NULL;
+ #endif
+-#ifdef CONFIG_SELINUX
+-      is_flask_enabled_flag = is_flask_enabled();
+-#endif
+-
+       all_fmt = LIST_SHORT | DISP_NORMAL | STYLE_AUTO
+ #ifdef CONFIG_FEATURE_LS_TIMESTAMPS
+               | TIME_MOD
+diff -Nur busybox-1.00/coreutils/md5_sha1_sum.c busybox/coreutils/md5_sha1_sum.c
+--- busybox-1.00/coreutils/md5_sha1_sum.c      2004-04-14 19:51:09.000000000 +0200
++++ busybox/coreutils/md5_sha1_sum.c   2005-06-04 08:20:13.000000000 +0200
+@@ -49,38 +49,25 @@
+ static uint8_t *hash_file(const char *filename, uint8_t hash_algo)
+ {
+-      uint8_t *hash_value_bin;
+-      uint8_t *hash_value = NULL;
+-      uint8_t hash_length;
+-      int src_fd;
+-
+-      if (strcmp(filename, "-") == 0) {
+-              src_fd = STDIN_FILENO;
+-      } else {
+-              src_fd = open(filename, O_RDONLY);
+-      }
+-
+-      if (hash_algo == HASH_MD5) {
+-              hash_length = 16;
+-      } else {
+-              hash_length = 20;
+-      }
+-
+-      hash_value_bin = xmalloc(hash_length);
+-
+-      if ((src_fd != -1) && (hash_fd(src_fd, -1, hash_algo, hash_value_bin) != -2)) {
+-              hash_value = hash_bin_to_hex(hash_value_bin, hash_length);
+-      } else {
++      int src_fd = strcmp(filename, "-") == 0 ? STDIN_FILENO :
++              open(filename, O_RDONLY);
++      if (src_fd == -1) {
+               bb_perror_msg("%s", filename);
++              return NULL;
++      } else {
++              uint8_t *hash_value;
++              RESERVE_CONFIG_UBUFFER(hash_value_bin, 20);
++              hash_value = hash_fd(src_fd, -1, hash_algo, hash_value_bin) != -2 ?
++                      hash_bin_to_hex(hash_value_bin, hash_algo == HASH_MD5 ? 16 : 20) :
++                      NULL;
++              RELEASE_CONFIG_BUFFER(hash_value_bin);
++              close(src_fd);
++              return hash_value;
+       }
+-
+-      close(src_fd);
+-
+-      return(hash_value);
+ }
+ /* This could become a common function for md5 as well, by using md5_stream */
+-extern int hash_files(int argc, char **argv, const uint8_t hash_algo)
++static int hash_files(int argc, char **argv, const uint8_t hash_algo)
+ {
+       int return_value = EXIT_SUCCESS;
+       uint8_t *hash_value;
+diff -Nur busybox-1.00/coreutils/nice.c busybox/coreutils/nice.c
+--- busybox-1.00/coreutils/nice.c      1970-01-01 01:00:00.000000000 +0100
++++ busybox/coreutils/nice.c   2005-06-04 08:20:13.000000000 +0200
+@@ -0,0 +1,86 @@
++/* vi: set sw=4 ts=4: */
++/*
++ * nice implementation for busybox
++ *
++ * Copyright (C) 2005  Manuel Novoa III  <mjn3@codepoet.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <limits.h>
++#include <errno.h>
++#include <unistd.h>
++#include <sys/time.h>
++#include <sys/resource.h>
++#include "busybox.h"
++
++static inline int int_add_no_wrap(int a, int b)
++{
++      int s = a + b;
++
++      if (b < 0) {
++              if (s > a) s = INT_MIN;
++      } else {
++              if (s < a) s = INT_MAX;
++      }
++
++      return s;
++}
++
++int nice_main(int argc, char **argv)
++{
++      static const char Xetpriority_msg[] = "cannot %cet priority";
++
++      int old_priority, adjustment;
++
++      errno = 0;                       /* Needed for getpriority error detection. */
++      old_priority = getpriority(PRIO_PROCESS, 0);
++      if (errno) {
++              bb_perror_msg_and_die(Xetpriority_msg, 'g');
++      }
++
++      if (!*++argv) { /* No args, so (GNU) output current nice value. */
++              bb_printf("%d\n", old_priority);
++              bb_fflush_stdout_and_exit(EXIT_SUCCESS);
++      }
++
++      adjustment = 10;                        /* Set default adjustment. */
++
++      if ((argv[0][0] == '-') && (argv[0][1] == 'n') && !argv[0][2]) { /* "-n" */
++              if (argc < 4) {                 /* Missing priority and/or utility! */
++                      bb_show_usage();
++              }
++              adjustment = bb_xgetlarg(argv[1], 10, INT_MIN, INT_MAX);
++              argv += 2;
++      }
++
++      {  /* Set our priority.  Handle integer wrapping for old + adjust. */
++              int new_priority = int_add_no_wrap(old_priority, adjustment);
++
++              if (setpriority(PRIO_PROCESS, 0, new_priority) < 0) {
++                      bb_perror_msg_and_die(Xetpriority_msg, 's');
++              }
++      }
++      
++      execvp(*argv, argv);            /* Now exec the desired program. */
++
++      /* The exec failed... */
++      bb_default_error_retval = (errno == ENOENT) ? 127 : 126; /* SUSv3 */
++      bb_perror_msg_and_die("%s", *argv);
++}
+diff -Nur busybox-1.00/coreutils/printenv.c busybox/coreutils/printenv.c
+--- busybox-1.00/coreutils/printenv.c  1970-01-01 01:00:00.000000000 +0100
++++ busybox/coreutils/printenv.c       2005-06-04 08:20:13.000000000 +0200
+@@ -0,0 +1,53 @@
++/*
++ * printenv implementation for busybox
++ *
++ * Copyright (C) 2005 by Erik Andersen <andersen@codepoet.org>
++ * Copyright (C) 2005 by Mike Frysinger <vapier@gentoo.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++
++#include <stdio.h>
++#include <string.h>
++#include <stdlib.h>
++#include "busybox.h"
++
++int printenv_main(int argc, char **argv)
++{
++      extern char **environ;
++      int e = 0;
++
++      /* no variables specified, show whole env */
++      if (argc == 1)
++              while (environ[e])
++                      puts(environ[e++]);
++
++      /* search for specified variables and print them out if found */
++      else {
++              int i;
++              size_t l;
++              char *arg, *env;
++
++              for (i=1; (arg = argv[i]); ++i)
++                      for (; (env = environ[e]); ++e) {
++                              l = strlen(arg);
++                              if (!strncmp(env, arg, l) && env[l] == '=')
++                                      puts(env + l + 1);
++                      }
++      }
++
++      bb_fflush_stdout_and_exit(0);
++}
+diff -Nur busybox-1.00/coreutils/sort.c busybox/coreutils/sort.c
+--- busybox-1.00/coreutils/sort.c      2003-03-19 10:11:34.000000000 +0100
++++ busybox/coreutils/sort.c   2005-06-04 08:20:13.000000000 +0200
+@@ -1,8 +1,8 @@
+ /* vi: set sw=4 ts=4: */
+ /*
+- * Mini sort implementation for busybox
++ * SuS3 compliant sort implementation for busybox
+  *
+- * Copyright (C) 2000 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
++ * Copyright (C) 2004 by Rob Landley <rob@landley.net>
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -18,83 +18,321 @@
+  * along with this program; if not, write to the Free Software
+  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+  *
++ * See SuS3 sort standard at:
++ * http://www.opengroup.org/onlinepubs/007904975/utilities/sort.html
+  */
+-/* BB_AUDIT SUSv3 _NOT_ compliant -- a number of options are not supported. */
+-/* http://www.opengroup.org/onlinepubs/007904975/utilities/sort.html */
+-
+-/* Mar 16, 2003      Manuel Novoa III   (mjn3@codepoet.org)
+- *
+- * Now does proper error checking on i/o.  Plus some space savings.
+- */
+-
++#include <ctype.h>
++#include <math.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
++#include <time.h>
+ #include <unistd.h>
+ #include "busybox.h"
+-#include "libcoreutils/coreutils.h"
+-static int compare_ascii(const void *x, const void *y)
++static int global_flags;
++
++/*
++      sort [-m][-o output][-bdfinru][-t char][-k keydef]... [file...]
++      sort -c [-bdfinru][-t char][-k keydef][file]
++*/
++
++/* These are sort types */
++#define FLAG_n                        1               /* Numeric sort */
++#define FLAG_g                        2               /* Sort using strtod() */
++#define FLAG_M                        4               /* Sort date */
++/* ucsz apply to root level only, not keys.  b at root level implies bb */
++#define FLAG_u                        8               /* Unique */
++#define FLAG_c                        16              /* Check: no output, exit(!ordered) */
++#define FLAG_s                        32              /* Stable sort, no ascii fallback at end */
++#define FLAG_z                        64              /* Input is null terminated, not \n */
++/* These can be applied to search keys, the previous four can't */
++#define FLAG_b                        128             /* Ignore leading blanks */
++#define FLAG_r                        256             /* Reverse */
++#define FLAG_d                        512             /* Ignore !(isalnum()|isspace()) */
++#define FLAG_f                        1024    /* Force uppercase */
++#define FLAG_i                        2048    /* Ignore !isprint() */
++#define FLAG_bb                       32768   /* Ignore trailing blanks  */
++
++
++#ifdef CONFIG_SORT_BIG
++static char key_separator;
++
++static struct sort_key
+ {
+-      return strcmp(*(char **)x, *(char **)y);
+-}
++      struct sort_key *next_key;      /* linked list */
++      unsigned short range[4];        /* start word, start char, end word, end char */
++      int flags;
++} *key_list;
+-static int compare_numeric(const void *x, const void *y)
++static char *get_key(char *str, struct sort_key *key, int flags)
+ {
+-      int z = atoi(*(char **)x) - atoi(*(char **)y);
+-      return z ? z : strcmp(*(char **)x, *(char **)y);
++      int start=0,end,len,i,j;
++
++      /* Special case whole string, so we don't have to make a copy */
++      if(key->range[0]==1 && !key->range[1] && !key->range[2] && !key->range[3]
++              && !(flags&(FLAG_b&FLAG_d&FLAG_f&FLAG_i&FLAG_bb))) return str;
++      /* Find start of key on first pass, end on second pass*/
++      len=strlen(str);
++
++      for(j=0;j<2;j++) {
++              if(!key->range[2*j]) end=len;
++              /* Loop through fields */
++              else {
++                      end=0;
++                      for(i=1;i<key->range[2*j]+j;i++) {
++                              /* Skip leading blanks or first separator */
++                              if(str[end]) {
++                                      if(key_separator) {
++                                              if(str[end]==key_separator) end++;
++                                      } else if(isspace(str[end]))
++                                              while(isspace(str[end])) end++;
++                              }
++                              /* Skip body of key */
++                              for(;str[end];end++) {
++                                      if(key_separator) {
++                                              if(str[end]==key_separator) break;
++                                      } else if(isspace(str[end])) break;
++                              }
++                      }
++              }
++              if(!j) start=end;
++      }
++      /* Key with explicit separator starts after separator */
++      if(key_separator && str[start]==key_separator) start++;
++      /* Strip leading whitespace if necessary */
++      if(flags&FLAG_b) while(isspace(str[start])) start++;
++      /* Strip trailing whitespace if necessary */
++      if(flags&FLAG_bb) while(end>start && isspace(str[end-1])) end--;
++      /* Handle offsets on start and end */
++      if(key->range[3]) {
++              end+=key->range[3]-1;
++              if(end>len) end=len;
++      }
++      if(key->range[1]) {
++              start+=key->range[1]-1;
++              if(start>len) start=len;
++      }
++      /* Make the copy */
++      if(end<start) end=start;
++      str=bb_xstrndup(str+start,end-start);
++      /* Handle -d */
++      if(flags&FLAG_d) {
++              for(start=end=0;str[end];end++)
++                      if(isspace(str[end]) || isalnum(str[end])) str[start++]=str[end];
++              str[start]=0;
++      }
++      /* Handle -i */
++      if(flags&FLAG_i) {
++              for(start=end=0;str[end];end++)
++                      if(isprint(str[end])) str[start++]=str[end];
++              str[start]=0;
++      }
++      /* Handle -f */
++      if(flags*FLAG_f) for(i=0;str[i];i++) str[i]=toupper(str[i]);
++
++      return str;
+ }
+-int sort_main(int argc, char **argv)
++static struct sort_key *add_key(void)
+ {
+-      FILE *fp;
+-      char *line, **lines = NULL;
+-      int i, nlines = 0, inc;
+-      int (*compare)(const void *, const void *) = compare_ascii;
++      struct sort_key **pkey=&key_list;
++      while(*pkey) pkey=&((*pkey)->next_key);
++      return *pkey=xcalloc(1,sizeof(struct sort_key));
++}
+-      int flags;
++#define GET_LINE(fp) (global_flags&FLAG_z) ? bb_get_chunk_from_file(fp) \
++                                                                                 : bb_get_chomped_line_from_file(fp)
++#else
++#define GET_LINE(fp)          bb_get_chomped_line_from_file(fp)
++#endif
+-      bb_default_error_retval = 2;
++/* Iterate through keys list and perform comparisons */
++static int compare_keys(const void *xarg, const void *yarg)
++{
++      int flags=global_flags,retval=0;
++      char *x,*y;
+-      flags = bb_getopt_ulflags(argc, argv, "nru");
+-      if (flags & 1) {
+-              compare = compare_numeric;
++#ifdef CONFIG_SORT_BIG
++      struct sort_key *key;
++      
++      for(key=key_list;!retval && key;key=key->next_key) {
++              flags=(key->flags) ? key->flags : global_flags;
++              /* Chop out and modify key chunks, handling -dfib */
++              x=get_key(*(char **)xarg,key,flags);
++              y=get_key(*(char **)yarg,key,flags);
++#else
++      /* This curly bracket serves no purpose but to match the nesting
++         level of the for() loop we're not using */
++      {
++              x=*(char **)xarg;
++              y=*(char **)yarg;
++#endif
++              /* Perform actual comparison */
++              switch(flags&7) {
++                      default:
++                              bb_error_msg_and_die("Unknown sort type.");
++                              break;
++                      /* Ascii sort */
++                      case 0:
++                              retval=strcmp(x,y);
++                              break;
++#ifdef CONFIG_SORT_BIG
++                      case FLAG_g:
++                      {
++                              char *xx,*yy;
++                              double dx=strtod(x,&xx), dy=strtod(y,&yy);
++                              /* not numbers < NaN < -infinity < numbers < +infinity) */
++                              if(x==xx) retval=(y==yy ? 0 : -1);
++                              else if(y==yy) retval=1;
++                              else if(isnan(dx)) retval=isnan(dy) ? 0 : -1;
++                              else if(isnan(dy)) retval=1;
++                              else if(isinf(dx)) {
++                                      if(dx<0) retval=((isinf(dy) && dy<0) ? 0 : -1);
++                                      else retval=((isinf(dy) && dy>0) ? 0 : 1);
++                              } else if(isinf(dy)) retval=dy<0 ? 1 : -1;
++                              else retval=dx>dy ? 1 : (dx<dy ? -1 : 0);
++                              break;
++                      }
++                      case FLAG_M:
++                      {
++                              struct tm thyme;
++                              int dx;
++                              char *xx,*yy;
++
++                              xx=strptime(x,"%b",&thyme);
++                              dx=thyme.tm_mon;
++                              yy=strptime(y,"%b",&thyme);
++                              if(!xx) retval=(!yy ? 0 : -1);
++                              else if(!yy) retval=1;
++                              else retval=(dx==thyme.tm_mon ? 0 : dx-thyme.tm_mon);
++                              break;
++                      }
++                      /* Full floating point version of -n */
++                      case FLAG_n:
++                      {
++                              double dx=atof(x),dy=atof(y);
++                              retval=dx>dy ? 1 : (dx<dy ? -1 : 0);
++                              break;
++                      }
++              }
++              /* Free key copies. */
++              if(x!=*(char **)xarg) free(x);
++              if(y!=*(char **)yarg) free(y);
++              if(retval) break;
++#else
++                      /* Integer version of -n for tiny systems */
++                      case FLAG_n:
++                              retval=atoi(x)-atoi(y);
++                              break;
++              }
++#endif
+       }
++      /* Perform fallback sort if necessary */
++      if(!retval && !(global_flags&FLAG_s))
++                      retval=strcmp(*(char **)xarg, *(char **)yarg);
++      return ((flags&FLAG_r)?-1:1)*retval;
++}
+-      argv += optind;
+-      if (!*argv) {
+-              *--argv = "-";
+-      }
++int sort_main(int argc, char **argv)
++{
++      FILE *fp,*outfile=NULL;
++      int linecount=0,i,flag;
++      char *line,**lines=NULL,c,*optlist="ngMucszbrdfimS:T:o:k:t:";
+-      do {
+-              fp = xgetoptfile_sort_uniq(argv, "r");
+-              while ((line = bb_get_chomped_line_from_file(fp)) != NULL) {
+-                      lines = xrealloc(lines, sizeof(char *) * (nlines + 1));
+-                      lines[nlines++] = line;
++      bb_default_error_retval = 2;
++      /* Parse command line options */
++      while((c=getopt(argc,argv,optlist))>0) {
++              line=index(optlist,c);
++              if(!line) bb_show_usage();
++              switch(*line) {
++#ifdef CONFIG_SORT_BIG
++                      case 'o':
++                              if(outfile) bb_error_msg_and_die("Too many -o.");
++                              outfile=bb_xfopen(optarg,"w");
++                              break;
++                      case 't':
++                              if(key_separator || optarg[1])
++                                      bb_error_msg_and_die("Too many -t.");
++                              key_separator=*optarg;
++                              break;
++                      /* parse sort key */
++                      case 'k':
++                      {
++                              struct sort_key *key=add_key();
++                              char *temp, *temp2;
++
++                              temp=optarg;
++                              for(i=0;*temp;) {
++                                      /* Start of range */
++                                      key->range[2*i]=(unsigned short)strtol(temp,&temp,10);
++                                      if(*temp=='.')
++                                              key->range[(2*i)+1]=(unsigned short)strtol(temp+1,&temp,10);
++                                      for(;*temp;temp++) {
++                                              if(*temp==',' && !i++) {
++                                                      temp++;
++                                                      break;
++                                              } /* no else needed: fall through to syntax error
++                                                       because comma isn't in optlist */
++                                              temp2=index(optlist,*temp);
++                                              flag=(1<<(temp2-optlist));
++                                              if(!temp2 || (flag>FLAG_M && flag<FLAG_b))
++                                                      bb_error_msg_and_die("Unknown key option.");
++                                              /* b after , means strip _trailing_ space */
++                                              if(i && flag==FLAG_b) flag=FLAG_bb;
++                                              key->flags|=flag;
++                                      }
++                              }
++                              break;
++                      }
++#endif
++                      default:
++                              global_flags|=(1<<(line-optlist));
++                              /* global b strips leading and trailing spaces */
++                              if(global_flags&FLAG_b) global_flags|=FLAG_bb;
++                              break;
+               }
+-              bb_xferror(fp, *argv);
+-              bb_fclose_nonstdin(fp);
+-      } while (*++argv);
+-
+-      /* sort it */
+-      qsort(lines, nlines, sizeof(char *), compare);
+-
+-      /* print it */
+-      i = 0;
+-      --nlines;
+-      if ((inc = 1 - (flags & 2)) < 0) {      /* reverse */
+-              i = nlines;
+       }
+-      flags &= 4;
+-
+-      while (nlines >= 0) {
+-              if (!flags || !nlines || strcmp(lines[i+inc], lines[i])) {
+-                      puts(lines[i]);
++      /* Open input files and read data */
++      for(i=argv[optind] ? optind : optind-1;argv[i];i++) {
++              if(i<optind || (*argv[i]=='-' && !argv[i][1])) fp=stdin;
++              else fp=bb_xfopen(argv[i],"r");
++              for(;;) {
++                      line=GET_LINE(fp);
++                      if(!line) break;
++                      if(!(linecount&63))
++                              lines=xrealloc(lines, sizeof(char *)*(linecount+64));
++                      lines[linecount++]=line;
+               }
+-              i += inc;
+-              --nlines;
++              fclose(fp);
+       }
+-
++#ifdef CONFIG_SORT_BIG
++      /* if no key, perform alphabetic sort */
++    if(!key_list) add_key()->range[0]=1;
++      /* handle -c */ 
++      if(global_flags&FLAG_c) {
++              int j=(global_flags&FLAG_u) ? -1 : 0;
++              for(i=1;i<linecount;i++)
++                      if(compare_keys(&lines[i-1],&lines[i])>j) {
++                              fprintf(stderr,"Check line %d\n",i);
++                              return 1;
++                      }
++              return 0;
++      }
++#endif
++      /* Perform the actual sort */
++      qsort(lines,linecount,sizeof(char *),compare_keys);
++      /* handle -u */
++      if(global_flags&FLAG_u) {
++              for(flag=0,i=1;i<linecount;i++) {
++                      if(!compare_keys(&lines[flag],&lines[i])) free(lines[i]);
++                      else lines[++flag]=lines[i];
++              }
++              if(linecount) linecount=flag+1;
++      }
++      /* Print it */
++      if(!outfile) outfile=stdout;
++      for(i=0;i<linecount;i++) fprintf(outfile,"%s\n",lines[i]);
+       bb_fflush_stdout_and_exit(EXIT_SUCCESS);
+ }
+diff -Nur busybox-1.00/coreutils/stat.c busybox/coreutils/stat.c
+--- busybox-1.00/coreutils/stat.c      1970-01-01 01:00:00.000000000 +0100
++++ busybox/coreutils/stat.c   2005-06-04 08:20:13.000000000 +0200
+@@ -0,0 +1,564 @@
++/*
++ * stat -- display file or file system status
++ *
++ * Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation.
++ * Copyright (C) 2005 by Erik Andersen <andersen@codepoet.org>
++ * Copyright (C) 2005 by Mike Frysinger <vapier@gentoo.org>
++ *
++ * Written by Michael Meskes
++ * Taken from coreutils and turned into a busybox applet by Mike Frysinger
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++
++#include <stdio.h>
++#include <sys/types.h>
++#include <pwd.h>
++#include <grp.h>
++#include <sys/vfs.h>
++#include <time.h>
++#include <getopt.h>
++#include <sys/stat.h>
++#include <string.h>
++#include "busybox.h"
++
++/* vars to control behavior */
++#define OPT_TERSE 2
++#define OPT_DEREFERNCE 4
++static long flags;
++
++static char const *file_type(struct stat const *st)
++{
++      /* See POSIX 1003.1-2001 XCU Table 4-8 lines 17093-17107 
++       * for some of these formats.
++       * To keep diagnostics grammatical in English, the 
++       * returned string must start with a consonant.
++       */
++      if (S_ISREG(st->st_mode))  return st->st_size == 0 ? "regular empty file" : "regular file";
++      if (S_ISDIR(st->st_mode))  return "directory";
++      if (S_ISBLK(st->st_mode))  return "block special file";
++      if (S_ISCHR(st->st_mode))  return "character special file";
++      if (S_ISFIFO(st->st_mode)) return "fifo";
++      if (S_ISLNK(st->st_mode))  return "symbolic link";
++      if (S_ISSOCK(st->st_mode)) return "socket";
++      if (S_TYPEISMQ(st))        return "message queue";
++      if (S_TYPEISSEM(st))       return "semaphore";
++      if (S_TYPEISSHM(st))       return "shared memory object";
++#ifdef S_TYPEISTMO
++      if (S_TYPEISTMO(st))       return "typed memory object";
++#endif
++      return "weird file";
++}
++
++static char const *human_time(time_t t)
++{
++      static char *str;
++      str = ctime(&t);
++      str[strlen(str)-1] = '\0';
++      return str;
++}
++
++/* Return the type of the specified file system.
++ * Some systems have statfvs.f_basetype[FSTYPSZ]. (AIX, HP-UX, and Solaris)
++ * Others have statfs.f_fstypename[MFSNAMELEN]. (NetBSD 1.5.2)
++ * Still others have neither and have to get by with f_type (Linux).
++ */
++static char const *human_fstype(long f_type)
++{
++      int i;
++      static struct types {
++              long type;
++              char *fs;
++      } humantypes[] = {
++              { 0xADFF,     "affs" },
++              { 0x1Cd1,     "devpts" },
++              { 0x137D,     "ext" },
++              { 0xEF51,     "ext2" },
++              { 0xEF53,     "ext2/ext3" },
++              { 0x3153464a, "jfs" },
++              { 0x58465342, "xfs" },
++              { 0xF995E849, "hpfs" },
++              { 0x9660,     "isofs" },
++              { 0x4000,     "isofs" },
++              { 0x4004,     "isofs" },
++              { 0x137F,     "minix" },
++              { 0x138F,     "minix (30 char.)" },
++              { 0x2468,     "minix v2" },
++              { 0x2478,     "minix v2 (30 char.)" },
++              { 0x4d44,     "msdos" },
++              { 0x4006,     "fat" },
++              { 0x564c,     "novell" },
++              { 0x6969,     "nfs" },
++              { 0x9fa0,     "proc" },
++              { 0x517B,     "smb" },
++              { 0x012FF7B4, "xenix" },
++              { 0x012FF7B5, "sysv4" },
++              { 0x012FF7B6, "sysv2" },
++              { 0x012FF7B7, "coh" },
++              { 0x00011954, "ufs" },
++              { 0x012FD16D, "xia" },
++              { 0x5346544e, "ntfs" },
++              { 0x1021994,  "tmpfs" },
++              { 0x52654973, "reiserfs" },
++              { 0x28cd3d45, "cramfs" },
++              { 0x7275,     "romfs" },
++              { 0x858458f6, "romfs" },
++              { 0x73717368, "squashfs" },
++              { 0x62656572, "sysfs" },
++              { 0, "UNKNOWN" },
++              { 0, NULL }
++      };
++      for (i=0; humantypes[i].type; ++i)
++              if (humantypes[i].type == f_type)
++                      return humantypes[i].fs;
++      return humantypes[i].fs;
++}
++
++#ifdef CONFIG_FEATURE_STAT_FORMAT
++/* print statfs info */
++static void print_statfs(char *pformat, size_t buf_len, char m, 
++                         char const *filename, void const *data)
++{
++      struct statfs const *statfsbuf = data;
++
++      switch (m) {
++      case 'n':
++              strncat(pformat, "s", buf_len);
++              printf(pformat, filename);
++              break;
++      case 'i':
++              strncat(pformat, "Lx", buf_len);
++              printf(pformat, statfsbuf->f_fsid);
++              break;
++      case 'l':
++              strncat(pformat, "lu", buf_len);
++              printf(pformat, statfsbuf->f_namelen);
++              break;
++      case 't':
++              strncat(pformat, "lx", buf_len);
++              printf(pformat, (unsigned long int) (statfsbuf->f_type));  /* no equiv. */
++              break;
++      case 'T':
++              strncat(pformat, "s", buf_len);
++              printf(pformat, human_fstype(statfsbuf->f_type));
++              break;
++      case 'b':
++              strncat(pformat, "ld", buf_len);
++              printf(pformat, (intmax_t) (statfsbuf->f_blocks));
++              break;
++      case 'f':
++              strncat(pformat, "ld", buf_len);
++              printf(pformat, (intmax_t) (statfsbuf->f_bfree));
++              break;
++      case 'a':
++              strncat(pformat, "ld", buf_len);
++              printf(pformat, (intmax_t) (statfsbuf->f_bavail));
++              break;
++      case 's':
++              strncat(pformat, "lu", buf_len);
++              printf(pformat, (unsigned long int) (statfsbuf->f_bsize));
++              break;
++      case 'S': {
++              unsigned long int frsize = statfsbuf->f_frsize;
++              if (!frsize)
++                      frsize = statfsbuf->f_bsize;
++              strncat(pformat, "lu", buf_len);
++              printf(pformat, frsize);
++              break;
++      }
++      case 'c':
++              strncat(pformat, "ld", buf_len);
++              printf(pformat, (intmax_t) (statfsbuf->f_files));
++              break;
++      case 'd':
++              strncat(pformat, "ld", buf_len);
++              printf(pformat, (intmax_t) (statfsbuf->f_ffree));
++              break;
++      default:
++              strncat(pformat, "c", buf_len);
++              printf(pformat, m);
++              break;
++      }
++}
++
++/* print stat info */
++static void print_stat(char *pformat, size_t buf_len, char m, 
++                       char const *filename, void const *data)
++{
++#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
++      struct stat *statbuf = (struct stat *) data;
++      struct passwd *pw_ent;
++      struct group *gw_ent;
++
++      switch (m) {
++      case 'n':
++              strncat(pformat, "s", buf_len);
++              printf(pformat, filename);
++              break;
++      case 'N':
++              strncat(pformat, "s", buf_len);
++              if (S_ISLNK(statbuf->st_mode)) {
++                      char *linkname = xreadlink(filename);
++                      if (linkname == NULL) {
++                              bb_perror_msg("cannot read symbolic link '%s'", filename);
++                              return;
++                      }
++                      /*printf("\"%s\" -> \"%s\"", filename, linkname); */
++                      printf(pformat, filename);
++                      printf(" -> ");
++                      printf(pformat, linkname);
++              } else {
++                      printf(pformat, filename);
++              }
++              break;
++      case 'd':
++              strncat(pformat, "lu", buf_len);
++              printf(pformat, (uintmax_t) statbuf->st_dev);
++              break;
++      case 'D':
++              strncat(pformat, "lx", buf_len);
++              printf(pformat, (uintmax_t) statbuf->st_dev);
++              break;
++      case 'i':
++              strncat(pformat, "lu", buf_len);
++              printf(pformat, (uintmax_t) statbuf->st_ino);
++              break;
++      case 'a':
++              strncat(pformat, "lo", buf_len);
++              printf(pformat, (unsigned long int) (statbuf->st_mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)));
++              break;
++      case 'A':
++              strncat(pformat, "s", buf_len);
++              printf(pformat, bb_mode_string(statbuf->st_mode));
++              break;
++      case 'f':
++              strncat(pformat, "lx", buf_len);
++              printf(pformat, (unsigned long int) statbuf->st_mode);
++              break;
++      case 'F':
++              strncat(pformat, "s", buf_len);
++              printf(pformat, file_type(statbuf));
++              break;
++      case 'h':
++              strncat(pformat, "lu", buf_len);
++              printf(pformat, (unsigned long int) statbuf->st_nlink);
++              break;
++      case 'u':
++              strncat(pformat, "lu", buf_len);
++              printf(pformat, (unsigned long int) statbuf->st_uid);
++              break;
++      case 'U':
++              strncat(pformat, "s", buf_len);
++              setpwent();
++              pw_ent = getpwuid(statbuf->st_uid);
++              printf(pformat, (pw_ent != 0L) ? pw_ent->pw_name : "UNKNOWN");
++              break;
++      case 'g':
++              strncat(pformat, "lu", buf_len);
++              printf(pformat, (unsigned long int) statbuf->st_gid);
++              break;
++      case 'G':
++              strncat(pformat, "s", buf_len);
++              setgrent();
++              gw_ent = getgrgid(statbuf->st_gid);
++              printf(pformat, (gw_ent != 0L) ? gw_ent->gr_name : "UNKNOWN");
++              break;
++      case 't':
++              strncat(pformat, "lx", buf_len);
++              printf(pformat, (unsigned long int) major(statbuf->st_rdev));
++              break;
++      case 'T':
++              strncat(pformat, "lx", buf_len);
++              printf(pformat, (unsigned long int) minor(statbuf->st_rdev));
++              break;
++      case 's':
++              strncat(pformat, "lu", buf_len);
++              printf(pformat, (uintmax_t) (statbuf->st_size));
++              break;
++      case 'B':
++              strncat(pformat, "lu", buf_len);
++              printf(pformat, (unsigned long int) 512); //ST_NBLOCKSIZE
++              break;
++      case 'b':
++              strncat(pformat, "lu", buf_len);
++              printf(pformat, (uintmax_t) statbuf->st_blocks);
++              break;
++      case 'o':
++              strncat(pformat, "lu", buf_len);
++              printf(pformat, (unsigned long int) statbuf->st_blksize);
++              break;
++      case 'x':
++              strncat(pformat, "s", buf_len);
++              printf(pformat, human_time(statbuf->st_atime));
++              break;
++      case 'X':
++              strncat(pformat, TYPE_SIGNED(time_t) ? "ld" : "lu", buf_len);
++              printf(pformat, (unsigned long int) statbuf->st_atime);
++              break;
++      case 'y':
++              strncat(pformat, "s", buf_len);
++              printf(pformat, human_time(statbuf->st_mtime));
++              break;
++      case 'Y':
++              strncat(pformat, TYPE_SIGNED(time_t) ? "ld" : "lu", buf_len);
++              printf(pformat, (unsigned long int) statbuf->st_mtime);
++              break;
++      case 'z':
++              strncat(pformat, "s", buf_len);
++              printf(pformat, human_time(statbuf->st_ctime));
++              break;
++      case 'Z':
++              strncat(pformat, TYPE_SIGNED(time_t) ? "ld" : "lu", buf_len);
++              printf(pformat, (unsigned long int) statbuf->st_ctime);
++              break;
++      default:
++              strncat(pformat, "c", buf_len);
++              printf(pformat, m);
++              break;
++      }
++}
++
++static void print_it(char const *masterformat, char const *filename, 
++                     void (*print_func) (char *, size_t, char, char const *, void const *), 
++                     void const *data)
++{
++      char *b;
++
++      /* create a working copy of the format string */
++      char *format = bb_xstrdup(masterformat);
++
++      /* Add 2 to accommodate our conversion of the stat `%s' format string
++       * to the printf `%llu' one.  */
++      size_t n_alloc = strlen(format) + 2 + 1;
++      char *dest = xmalloc(n_alloc);
++
++      b = format;
++      while (b) {
++              char *p = strchr(b, '%');
++              if (p != NULL) {
++                      size_t len;
++                      *p++ = '\0';
++                      fputs(b, stdout);
++
++                      len = strspn(p, "#-+.I 0123456789");
++                      dest[0] = '%';
++                      memcpy(dest + 1, p, len);
++                      dest[1 + len] = 0;
++                      p += len;
++
++                      b = p + 1;
++                      switch (*p) {
++                              case '\0':
++                                      b = NULL;
++                                      /* fall through */
++                              case '%':
++                                      putchar('%');
++                                      break;
++                              default:
++                                      print_func(dest, n_alloc, *p, filename, data);
++                                      break;
++                      }
++
++              } else {
++                      fputs(b, stdout);
++                      b = NULL;
++              }
++      }
++
++      free(format);
++      free(dest);
++}
++#endif
++
++/* Stat the file system and print what we find.  */
++static int do_statfs(char const *filename, char const *format)
++{
++      struct statfs statfsbuf;
++
++      if (statfs(filename, &statfsbuf) != 0) {
++              bb_perror_msg("cannot read file system information for '%s'", filename);
++              return 0;
++      }
++
++#ifdef CONFIG_FEATURE_STAT_FORMAT
++      if (format == NULL)
++              format = (flags & OPT_TERSE
++                      ? "%n %i %l %t %s %S %b %f %a %c %d\n"
++                      : "  File: \"%n\"\n"
++                        "    ID: %-8i Namelen: %-7l Type: %T\n"
++                        "Block size: %-10s Fundamental block size: %S\n"
++                        "Blocks: Total: %-10b Free: %-10f Available: %a\n"
++                        "Inodes: Total: %-10c Free: %d\n");
++      print_it(format, filename, print_statfs, &statfsbuf);
++#else
++
++      format = (flags & OPT_TERSE
++              ? "%s %Lx %lu "
++              : "  File: \"%s\"\n"
++                "    ID: %-8Lx Namelen: %-7lu ");
++      printf(format,
++             filename,
++             statfsbuf.f_fsid,
++             statfsbuf.f_namelen);
++
++      if (flags & OPT_TERSE)
++              printf("%lx ", (unsigned long int) (statfsbuf.f_type));
++      else
++              printf("Type: %s\n", human_fstype(statfsbuf.f_type));
++
++      format = (flags & OPT_TERSE
++              ? "%lu %lu %ld %ld %ld %ld %ld\n"
++              : "Block size: %-10lu Fundamental block size: %lu\n"
++                "Blocks: Total: %-10ld Free: %-10ld Available: %ld\n"
++                "Inodes: Total: %-10ld Free: %ld\n");
++      printf(format,
++             (unsigned long int) (statfsbuf.f_bsize),
++             statfsbuf.f_frsize ? statfsbuf.f_frsize : statfsbuf.f_bsize,
++             (intmax_t) (statfsbuf.f_blocks),
++             (intmax_t) (statfsbuf.f_bfree),
++             (intmax_t) (statfsbuf.f_bavail),
++             (intmax_t) (statfsbuf.f_files),
++             (intmax_t) (statfsbuf.f_ffree));
++#endif
++
++      return 1;
++}
++
++/* stat the file and print what we find */
++static int do_stat(char const *filename, char const *format)
++{
++      struct stat statbuf;
++
++      if ((flags & OPT_DEREFERNCE ? stat : lstat) (filename, &statbuf) != 0) {
++              bb_perror_msg("cannot stat '%s'", filename);
++              return 0;
++      }
++
++#ifdef CONFIG_FEATURE_STAT_FORMAT
++      if (format == NULL) {
++              if (flags & OPT_TERSE) {
++                      format = "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o\n";
++              } else {
++                      if (S_ISBLK(statbuf.st_mode) || S_ISCHR(statbuf.st_mode)) {
++                              format =
++                                      "  File: \"%N\"\n"
++                                      "  Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
++                                      "Device: %Dh/%dd\tInode: %-10i  Links: %-5h"
++                                      " Device type: %t,%T\n"
++                                      "Access: (%04a/%10.10A)  Uid: (%5u/%8U)   Gid: (%5g/%8G)\n"
++                                      "Access: %x\n" "Modify: %y\n" "Change: %z\n";
++                      } else {
++                              format =
++                                      "  File: \"%N\"\n"
++                                      "  Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
++                                      "Device: %Dh/%dd\tInode: %-10i  Links: %h\n"
++                                      "Access: (%04a/%10.10A)  Uid: (%5u/%8U)   Gid: (%5g/%8G)\n"
++                                      "Access: %x\n" "Modify: %y\n" "Change: %z\n";
++                      }
++              }
++      }
++      print_it(format, filename, print_stat, &statbuf);
++#else
++      if (flags & OPT_TERSE) {
++              printf("%s %lu %lu %lx %lu %lu %lx %lu %lu %lx %lx %lu %lu %lu %lu\n",
++                     filename,
++                     (uintmax_t) (statbuf.st_size),
++                     (uintmax_t) statbuf.st_blocks,
++                     (unsigned long int) statbuf.st_mode,
++                     (unsigned long int) statbuf.st_uid,
++                     (unsigned long int) statbuf.st_gid,
++                     (uintmax_t) statbuf.st_dev,
++                     (uintmax_t) statbuf.st_ino,
++                     (unsigned long int) statbuf.st_nlink,
++                     (unsigned long int) major(statbuf.st_rdev),
++                     (unsigned long int) minor(statbuf.st_rdev),
++                     (unsigned long int) statbuf.st_atime,
++                     (unsigned long int) statbuf.st_mtime,
++                     (unsigned long int) statbuf.st_ctime,
++                     (unsigned long int) statbuf.st_blksize
++              );
++      } else {
++              char *linkname = NULL;
++
++              struct passwd *pw_ent;
++              struct group *gw_ent;
++              setgrent();
++              gw_ent = getgrgid(statbuf.st_gid);
++              setpwent();
++              pw_ent = getpwuid(statbuf.st_uid);
++
++              if (S_ISLNK(statbuf.st_mode))
++                      linkname = xreadlink(filename);
++              if (linkname)
++                      printf("  File: \"%s\" -> \"%s\"\n", filename, linkname);
++              else
++                      printf("  File: \"%s\"\n", filename);
++
++              printf("  Size: %-10lu\tBlocks: %-10lu IO Block: %-6lu %s\n"
++                     "Device: %lxh/%lud\tInode: %-10lu  Links: %-5lu",
++                     (uintmax_t) (statbuf.st_size),
++                     (uintmax_t) statbuf.st_blocks,
++                     (unsigned long int) statbuf.st_blksize,
++                     file_type(&statbuf),
++                     (uintmax_t) statbuf.st_dev,
++                     (uintmax_t) statbuf.st_dev,
++                     (uintmax_t) statbuf.st_ino,
++                     (unsigned long int) statbuf.st_nlink);
++              if (S_ISBLK(statbuf.st_mode) || S_ISCHR(statbuf.st_mode))
++                      printf(" Device type: %lx,%lx\n",
++                             (unsigned long int) major(statbuf.st_rdev),
++                             (unsigned long int) minor(statbuf.st_rdev));
++              else
++                      putchar('\n');
++              printf("Access: (%04lo/%10.10s)  Uid: (%5lu/%8s)   Gid: (%5lu/%8s)\n"
++                     "Access: %s\n" "Modify: %s\n" "Change: %s\n",
++                     (unsigned long int) (statbuf.st_mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)),
++                     bb_mode_string(statbuf.st_mode),
++                     (unsigned long int) statbuf.st_uid,
++                     (pw_ent != 0L) ? pw_ent->pw_name : "UNKNOWN",
++                     (unsigned long int) statbuf.st_gid,
++                     (gw_ent != 0L) ? gw_ent->gr_name : "UNKNOWN",
++                     human_time(statbuf.st_atime),
++                     human_time(statbuf.st_mtime),
++                     human_time(statbuf.st_ctime));
++      }
++#endif
++      return 1;
++}
++
++int stat_main(int argc, char **argv)
++{
++      int i;
++      char *format = NULL;
++      int ok = 1;
++      int (*statfunc)(char const *, char const *) = do_stat;
++
++      flags = bb_getopt_ulflags(argc, argv, "ftL"
++#ifdef CONFIG_FEATURE_STAT_FORMAT
++      "c:", &format
++#endif
++      );
++
++      if (flags & 1)                /* -f */
++              statfunc = do_statfs;
++      if (argc == optind)           /* files */
++              bb_show_usage();
++
++      for (i = optind; i < argc; ++i)
++              ok &= statfunc(argv[i], format);
++
++      return (ok ? EXIT_SUCCESS : EXIT_FAILURE);
++}
+diff -Nur busybox-1.00/coreutils/sum.c busybox/coreutils/sum.c
+--- busybox-1.00/coreutils/sum.c       1970-01-01 01:00:00.000000000 +0100
++++ busybox/coreutils/sum.c    2005-06-04 08:20:13.000000000 +0200
+@@ -0,0 +1,181 @@
++/*
++ * sum -- checksum and count the blocks in a file
++ *     Like BSD sum or SysV sum -r, except like SysV sum if -s option is given.
++ *
++ * Copyright (C) 86, 89, 91, 1995-2002, 2004 Free Software Foundation, Inc.
++ * Copyright (C) 2005 by Erik Andersen <andersen@codepoet.org>
++ * Copyright (C) 2005 by Mike Frysinger <vapier@gentoo.org>
++ *
++ * Written by Kayvan Aghaiepour and David MacKenzie
++ * Taken from coreutils and turned into a busybox applet by Mike Frysinger
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++
++#include <stdio.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <fcntl.h>
++#include <unistd.h>
++#include <getopt.h>
++
++#include "libbb.h"
++
++/* 1 if any of the files read were the standard input */
++static int have_read_stdin;
++
++/* make a little more readable and avoid using strcmp for just 2 bytes */
++#define IS_STDIN(s) (s[0] == '-' && s[1] == '\0')
++
++/* Calculate and print the rotated checksum and the size in 1K blocks
++   of file FILE, or of the standard input if FILE is "-".
++   If PRINT_NAME is >1, print FILE next to the checksum and size.
++   The checksum varies depending on sizeof (int).
++   Return 1 if successful.  */
++static int bsd_sum_file(const char *file, int print_name)
++{
++      register FILE *fp;
++      register int checksum = 0;          /* The checksum mod 2^16. */
++      register uintmax_t total_bytes = 0; /* The number of bytes. */
++      register int ch;                    /* Each character read. */
++
++      if (IS_STDIN(file)) {
++              fp = stdin;
++              have_read_stdin = 1;
++      } else {
++              fp = bb_wfopen(file, "r");
++              if (fp == NULL)
++                      return 0;
++      }
++
++      while ((ch = getc(fp)) != EOF) {
++              ++total_bytes;
++              checksum = (checksum >> 1) + ((checksum & 1) << 15);
++              checksum += ch;
++              checksum &= 0xffff;             /* Keep it within bounds. */
++      }
++
++      if (ferror(fp)) {
++              bb_perror_msg(file);
++              bb_fclose_nonstdin(fp);
++              return 0;
++      }
++
++      if (bb_fclose_nonstdin(fp) == EOF) {
++              bb_perror_msg(file);
++              return 0;
++      }
++
++      printf("%05d %5s ", checksum,
++             make_human_readable_str(total_bytes, 1, 1024));
++      if (print_name > 1)
++              puts(file);
++      else
++              printf("\n");
++
++      return 1;
++}
++
++/* Calculate and print the checksum and the size in 512-byte blocks
++   of file FILE, or of the standard input if FILE is "-".
++   If PRINT_NAME is >0, print FILE next to the checksum and size.
++   Return 1 if successful.  */
++static int sysv_sum_file(const char *file, int print_name)
++{
++      int fd;
++      unsigned char buf[8192];
++      uintmax_t total_bytes = 0;
++      int r;
++      int checksum;
++
++      /* The sum of all the input bytes, modulo (UINT_MAX + 1).  */
++      unsigned int s = 0;
++
++      if (IS_STDIN(file)) {
++              fd = 0;
++              have_read_stdin = 1;
++      } else {
++              fd = open(file, O_RDONLY);
++              if (fd == -1) {
++                      bb_perror_msg(file);
++                      return 0;
++              }
++      }
++
++      while (1) {
++              size_t i;
++              size_t bytes_read = safe_read(fd, buf, sizeof(buf));
++
++              if (bytes_read == 0)
++                      break;
++
++              if (bytes_read == -1) {
++                      bb_perror_msg(file);
++                      if (!IS_STDIN(file))
++                              close(fd);
++                      return 0;
++              }
++
++              for (i = 0; i < bytes_read; i++)
++                      s += buf[i];
++              total_bytes += bytes_read;
++      }
++
++      if (!IS_STDIN(file) && close(fd) == -1) {
++              bb_perror_msg(file);
++              return 0;
++      }
++
++      r = (s & 0xffff) + ((s & 0xffffffff) >> 16);
++      checksum = (r & 0xffff) + (r >> 16);
++
++      printf("%d %s ", checksum,
++             make_human_readable_str(total_bytes, 1, 512));
++      if (print_name)
++              puts(file);
++      else
++              printf("\n");
++
++      return 1;
++}
++
++int sum_main(int argc, char **argv)
++{
++      int flags;
++      int ok;
++      int files_given;
++      int (*sum_func)(const char *, int) = bsd_sum_file;
++
++      /* give the bsd func priority over sysv func */
++      flags = bb_getopt_ulflags(argc, argv, "sr");
++      if (flags & 1)
++              sum_func = sysv_sum_file;
++      if (flags & 2)
++              sum_func = bsd_sum_file;
++
++      have_read_stdin = 0;
++      files_given = argc - optind;
++      if (files_given <= 0)
++              ok = sum_func("-", files_given);
++      else
++              for (ok = 1; optind < argc; optind++)
++                      ok &= sum_func(argv[optind], files_given);
++
++      if (have_read_stdin && fclose(stdin) == EOF)
++              bb_perror_msg_and_die("-");
++
++      exit(ok ? EXIT_SUCCESS : EXIT_FAILURE);
++}
+diff -Nur busybox-1.00/coreutils/test.c busybox/coreutils/test.c
+--- busybox-1.00/coreutils/test.c      2004-08-11 04:45:47.000000000 +0200
++++ busybox/coreutils/test.c   2005-06-04 08:20:13.000000000 +0200
+@@ -51,7 +51,7 @@
+       unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"|
+               "-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S";
+-      binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
++      binary-operator ::= "="|"=="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
+                       "-nt"|"-ot"|"-ef";
+       operand ::= <any legal UNIX file name>
+ */
+@@ -135,6 +135,7 @@
+       "-L", FILSYM, UNOP}, {
+       "-S", FILSOCK, UNOP}, {
+       "=", STREQ, BINOP}, {
++      "==", STREQ, BINOP}, {
+       "!=", STRNE, BINOP}, {
+       "<", STRLT, BINOP}, {
+       ">", STRGT, BINOP}, {
+@@ -191,6 +192,11 @@
+                       bb_error_msg_and_die("missing ]");
+               argv[argc] = NULL;
+       }
++      if (strcmp(bb_applet_name, "[[") == 0) {
++              if (strcmp(argv[--argc], "]]"))
++                      bb_error_msg_and_die("missing ]]");
++              argv[argc] = NULL;
++      }
+       /* Implement special cases from POSIX.2, section 4.62.4 */
+       switch (argc) {
+       case 1:
+@@ -304,7 +310,7 @@
+       return strlen(*t_wp) > 0;
+ }
+-static int binop()
++static int binop(void)
+ {
+       const char *opnd1, *opnd2;
+       struct t_op const *op;
+@@ -531,7 +537,7 @@
+       return (-1);
+ }
+-static void initialize_group_array()
++static void initialize_group_array(void)
+ {
+       ngroups = getgroups(0, NULL);
+       group_array = xrealloc(group_array, ngroups * sizeof(gid_t));
+diff -Nur busybox-1.00/coreutils/watch.c busybox/coreutils/watch.c
+--- busybox-1.00/coreutils/watch.c     2003-03-19 10:11:34.000000000 +0100
++++ busybox/coreutils/watch.c  2005-06-04 08:20:13.000000000 +0200
+@@ -100,11 +100,10 @@
+                       //child
+                       close(1);
+                       dup(old_stdout);
+-                      if (execvp(*watched_argv, watched_argv)) {
+-                              bb_error_msg_and_die("Couldn't run command\n");
+-                      }
++                      execvp(*watched_argv, watched_argv);
++                      bb_perror_msg_and_die(*watched_argv);
+               } else {
+-                      bb_error_msg_and_die("Couldn't vfork\n");
++                      bb_perror_msg_and_die("vfork");
+               }
+       }
+ }
+diff -Nur busybox-1.00/coreutils/who.c busybox/coreutils/who.c
+--- busybox-1.00/coreutils/who.c       2004-03-15 09:28:22.000000000 +0100
++++ busybox/coreutils/who.c    2005-06-04 08:20:13.000000000 +0200
+@@ -74,7 +74,7 @@
+             } else
+                 printf("%-8s  ", "?");
+-            printf("%-12.12s   %s\n", ctime(&(ut->ut_tv.tv_sec)) + 4, ut->ut_host);
++            printf("%-12.12s   %s\n", ctime((time_t*)&(ut->ut_tv.tv_sec)) + 4, ut->ut_host);
+         }
+     }
+     endutent();
+diff -Nur busybox-1.00/debianutils/Config.in busybox/debianutils/Config.in
+--- busybox-1.00/debianutils/Config.in 2004-03-15 09:28:24.000000000 +0100
++++ busybox/debianutils/Config.in      2005-06-04 08:20:10.000000000 +0200
+@@ -24,6 +24,13 @@
+         This program reads a symbolic link and returns the name
+         of the file it points to
++config CONFIG_FEATURE_READLINK_FOLLOW
++      bool "  Enable canonicalization by following all symlinks (-f)"
++      default n
++      depends on CONFIG_READLINK
++      help
++        Enable the readlink option (-f).
++
+ config CONFIG_RUN_PARTS
+       bool "run-parts"
+       default n
+diff -Nur busybox-1.00/debianutils/readlink.c busybox/debianutils/readlink.c
+--- busybox-1.00/debianutils/readlink.c        2003-03-19 10:11:41.000000000 +0100
++++ busybox/debianutils/readlink.c     2005-06-04 08:20:10.000000000 +0200
+@@ -23,18 +23,38 @@
+ #include <errno.h>
+ #include <unistd.h>
+ #include <stdlib.h>
++#include <getopt.h>
+ #include "busybox.h"
++#ifdef CONFIG_FEATURE_READLINK_FOLLOW
++# define READLINK_FOLLOW      "f"
++# define READLINK_FLAG_f      (1 << 0)
++#else
++# define READLINK_FOLLOW      ""
++#endif
++
++static const char readlink_options[] = READLINK_FOLLOW;
++
+ int readlink_main(int argc, char **argv)
+ {
+       char *buf = NULL;
++      unsigned long opt = bb_getopt_ulflags(argc, argv, readlink_options);
++#ifdef CONFIG_FEATURE_READLINK_FOLLOW
++      RESERVE_CONFIG_BUFFER(resolved_path, PATH_MAX);
++#endif
+       /* no options, no getopt */
+-      if (argc != 2)
++      if (optind + 1 != argc)
+               bb_show_usage();
+-      buf = xreadlink(argv[1]);
++#ifdef CONFIG_FEATURE_READLINK_FOLLOW
++      if (opt & READLINK_FLAG_f) {
++              buf = realpath(argv[optind], resolved_path);
++      } else
++#endif
++              buf = xreadlink(argv[optind]);
++
+       if (!buf)
+               return EXIT_FAILURE;
+       puts(buf);
+diff -Nur busybox-1.00/debianutils/start_stop_daemon.c busybox/debianutils/start_stop_daemon.c
+--- busybox-1.00/debianutils/start_stop_daemon.c       2004-04-13 20:28:46.000000000 +0200
++++ busybox/debianutils/start_stop_daemon.c    2005-06-04 08:20:10.000000000 +0200
+@@ -238,7 +238,7 @@
+                       &startas, &cmdname, &signame, &userspec, &execname, &pidfile);
+       /* Check one and only one context option was given */
+-      if ((opt & 0x80000000UL) || (opt & (SSD_CTX_STOP | SSD_CTX_START)) == 0) {
++      if ((opt & BB_GETOPT_ERROR) || (opt & (SSD_CTX_STOP | SSD_CTX_START)) == 0) {
+               bb_show_usage();
+       }
+diff -Nur busybox-1.00/docs/autodocifier.pl busybox/docs/autodocifier.pl
+--- busybox-1.00/docs/autodocifier.pl  2004-04-06 17:26:25.000000000 +0200
++++ busybox/docs/autodocifier.pl       2005-06-04 08:20:06.000000000 +0200
+@@ -271,4 +271,4 @@
+ =cut
+-# $Id$
++# $Id$
+diff -Nur busybox-1.00/docs/busybox.net/FAQ.html busybox/docs/busybox.net/FAQ.html
+--- busybox-1.00/docs/busybox.net/FAQ.html     2004-10-13 11:42:10.000000000 +0200
++++ busybox/docs/busybox.net/FAQ.html  2005-06-04 08:20:06.000000000 +0200
+@@ -15,14 +15,15 @@
+ <li><a href="#bugs">I think I found a bug in BusyBox!  What should I do?!</a>
+ <li><a href="#job_control">Why do I keep getting "sh: can't access tty; job control
+       turned off" errors?  Why doesn't Control-C work within my shell?</a>
++<li><a href="#getting_started">How can I get started using BusyBox?</a>
+ <li><a href="#demanding">I demand that you to add &lt;favorite feature&gt; right now!   How come
+       you don't answer all my questions on the mailing list instantly?  I demand
+       that you help me with all of my problems <em>Right Now</em>!</a>
+-<li><a href="#getting_started">How can I get started using BusyBox?</a>
+ <li><a href="#helpme">I need help with BusyBox!  What should I do?</a>
+ <li><a href="#contracts">I need you to add &lt;favorite feature&gt;!  Are the BusyBox developers willing to
+       be paid in order to fix bugs or add in &lt;favorite feature&gt;?  Are you willing to provide
+       support contracts?</a>
++<li><a href="#external">Where can I find other small utilities since busybox does not include the features I want?</a></li>
+ <li><a href="#support">I think you guys are great and I want to help support your work!</a>
+@@ -76,6 +77,7 @@
+     with the generous terms of the GPL BusyBox license</a> you can ship BusyBox
+     as part of the software on your device.
++    <br>
+     <a href="#support">Please consider sharing some of the money you make.</a>
+@@ -84,49 +86,33 @@
+ <h2><a name="bugs">I think I found a bug in BusyBox!  What should I do?</h2>
+ <p>
+-    If you find a problem with BusyBox, please submit a detailed bug report to
+-    the BusyBox mailing list at <a href="mailto:busybox@mail.busybox.net">
+-    busybox@mail.busybox.net</a>.  Please do not send private email to Erik
+-    (the maintainer of BusyBox) asking for private help unless you are planning
+-    on paying for consulting services.  When we answer questions on the BusyBox
+-    mailing list, it helps everyone, while private answers help only you...
+-
+-    <p>
+-
+-    If you find bugs, please submit a detailed bug report to the BusyBox mailing
+-    list at busybox@mail.busybox.net.  A well-written bug report should include a
+-    transcript of a shell session that demonstrates the bad behavior and enables
+-    anyone else to duplicate the bug on their own machine. The following is such
+-    an example:
+-
+-<pre>
+-      To: busybox@mail.busybox.net
+-      From: diligent@testing.linux.org
+-      Subject: /bin/date doesn't work
+-      Package: BusyBox
+-      Version: 1.00
+-
+-      When I execute BusyBox 'date' it produces unexpected results.
+-      With GNU date I get the following output:
++<p>
+-              $ date
+-              Fri Oct  8 14:19:41 MDT 2004
++    If you simply need help with using or configuring BusyBox, please submit a
++    detailed description of your problem to the BusyBox mailing list at <a
++    href="mailto:busybox@mail.busybox.net"> busybox@mail.busybox.net</a>.
++    Please do not send private email to Erik (the maintainer of BusyBox) asking
++    for private help unless you are planning on paying for consulting services.
++    When we answer questions on the BusyBox mailing list, it helps everyone,
++    while private answers help only you...
+-      But when I use BusyBox date I get this instead:
++    <p>
+-              $ date
+-              illegal instruction
++    The developers of BusyBox are busy people, and have only so much they can
++    keep in their brains at a time.  As a result, bug reports sometimes get
++    lost when posted to the mailing list.  To prevent your bug report from
++    getting lost, if you find a bug in BusyBox, please use the <a
++    href="http://bugs.busybox.net/">BusyBox Bug and Patch Tracking System</a>
++    to submit a detailed bug report.
+-      I am using Debian unstable, kernel version 2.4.27 on a x86 system,
+-      and the latest uClibc from CVS.  Thanks for the wonderful program!
++    <p>
+-        -Diligent
+-</pre>
++    The same also applies to patches... Regardless of whether your patch is a
++    bug fix or adds shiney new features, please post your patch to the <a
++    href="http://bugs.busybox.net/">BusyBox Bug and Patch Tracking System</a>
++    to make certain it is properly considered.
+-    Note the careful description and use of examples showing not only what BusyBox
+-    does, but also a counter example showing what an equivalent GNU app does.  Bug
+-    reports lacking proper detail may never be fixed...  Thanks for understanding.
+ <hr />
+ <p>
+@@ -153,8 +139,8 @@
+     An easy method to build your own basic BusyBox based system, is to
+     follow these simple steps:
+     <ul>
+-      <li> Point your web browser <a href="/cgi-bin/cvsweb/buildroot/">here</a>
+-      <li> Click on "Download tarball"
++      <li> Point your web browser <a href="http://buildroot.uclibc.org/">here</a>
++      <li> Download a copy of buildroot
+       <li> Unpack the tarball on your Linux system somewhere
+       <li> run 'make' and configure things to taste.
+       <li> run 'unset CC'.   Some Linux systems (i.e. Gentoo) set 'CC'
+@@ -220,19 +206,25 @@
+       href="http://codepoet-consulting.com/">CodePoet Consulting</a> to bid
+     on your project.  If Erik is too busy to personally add your feature, there
+     are many other active BusyBox contributors who will almost certainly be able
+-    to help you out.  Erik can contact them privatly, and may even let you to
++    to help you out.  Erik can contact them privately, and may even let you to
+     post your request for services on the mailing list.
+ <hr />
+ <p>
++<h2><a name="external">Where can I find other small utilities since busybox 
++      does not include the features I want?</a></h2>
++<p>
++      We maintain such a <a href="tinyutils.html">list</a> on this site!
++
++
++<hr />
++<p>
+ <h2><a name="support">I think you guys are great and I want to help support your work!</a></h2>
+ <p>
+-    Wow, that would be great!  Erik personally pays for all the bandwidth, and
+-    all servers used for busybox.net out of his own pocket.  If you would like
+-    to make a donation to help support BusyBox, and/or request features, you
+-    can click here:
++    Wow, that would be great!  If you would like to make a donation to help
++    support BusyBox, and/or request features, you can click here:
+     <!-- Begin PayPal Logo -->
+     <center>
+@@ -321,4 +313,3 @@
+ <br>
+ <!--#include file="footer.html" -->
+-
+diff -Nur busybox-1.00/docs/busybox.net/cvs_anon.html busybox/docs/busybox.net/cvs_anon.html
+--- busybox-1.00/docs/busybox.net/cvs_anon.html        2004-03-15 09:28:29.000000000 +0100
++++ busybox/docs/busybox.net/cvs_anon.html     1970-01-01 01:00:00.000000000 +0100
+@@ -1,57 +0,0 @@
+-<!--#include file="header.html" -->
+-
+-
+-<h3>Anonymous CVS</h3>
+-
+-We allow anonymous (read-only) CVS access to everyone.  The first command you
+-need to run for anonymous CVS access is:
+-<pre>
+-cvs -d:pserver:anonymous@busybox.net:/var/cvs login</pre>
+-<p>
+-CVS will prompt you for a password. Just press the Enter key (there is no
+-password for anonymous access).  This step only needs to be done once, the first
+-time you attempt to access CVS.
+-<p>
+-Once the login is complete, you can then check the list of available
+-CVS modules by running the following command (all on one line):
+-<pre>
+-cvs -z3 -d:pserver:anonymous@busybox.net:/var/cvs co -c </pre>
+-
+-<p>
+-If you wish, you can then check out a local copy of any of the
+-available modules.  The following is an example of how to grab
+-a copy of busybox and tinylogin:
+-<pre>
+-    cvs -z3 -d:pserver:anonymous@busybox.net:/var/cvs co -P busybox tinylogin</pre>
+-This will create a directory called <b>busybox</b> and a directory called
+-<b>tinylogin</b> in the current directory.  These directories contain the
+-latest and greatest source code for busybox and tinylogin.
+-
+-<p>
+-If you are not already familiar with using CVS, I recommend you visit
+-this quick <a href="/cvs_howto.html">Introduction to CVS</a>.
+-
+-<p>
+-I usually create a ~/.cvsrc file with the following things in it, and I
+-recommend you should use the same:
+-<pre>
+-    -z3
+-    update -dP
+-    rdiff -u
+-    diff -ubBwpN
+-    checkout -P</pre>
+-
+-<p>
+-Once you've checked out a copy of the source tree, you can update your
+-source tree at any time so it is in sync with the latest and greatest by
+-running the command:
+-<pre>
+-cvs update</pre>
+-
+-Because you've only been granted anonymous access to the tree, you won't be
+-able to commit any changes. Changes can be submitted for inclusion by posting
+-them to the appropriate mailing list.  For those that are actively contributing
+-<a href="cvs_write.html">CVS write access</a> can be made available.
+-
+-<!--#include file="footer.html" -->
+-
+diff -Nur busybox-1.00/docs/busybox.net/cvs_howto.html busybox/docs/busybox.net/cvs_howto.html
+--- busybox-1.00/docs/busybox.net/cvs_howto.html       2004-03-15 09:28:29.000000000 +0100
++++ busybox/docs/busybox.net/cvs_howto.html    1970-01-01 01:00:00.000000000 +0100
+@@ -1,44 +0,0 @@
+-<!--#include file="header.html" -->
+-
+-
+-<h3>How to use CVS</h3>
+-
+-
+-If you want to know all the gory details, you will want to visit
+-<a href="http://www.cvshome.org/">the CVS main web page</a>.<p>
+-For the impatient, the following is probably about all you need to know:
+-<p>
+-
+-<dl>
+-    <dt><pre>cvs checkout -c</pre>
+-    <dd>Will list the modules available for checkout
+-    <dt><pre>cvs checkout &lt module name &gt</pre>
+-    <dd>Will checkout the named module
+-    <dt><pre>cvs co &lt module name &gt</pre>
+-    <dd>Same thing
+-    <dt><pre>cvs update</pre>
+-
+-    <dd>Updates your local archive so it is in sync with the repository
+-    -- your local updates are left intact.  Tries to merge upstream updates
+-    into your local updates.  You will see the following tags when it is
+-    updating your local repository: C means conflict, U means update,
+-    P means patched, and M means modified.
+-    <dt><pre>cvs up</pre>
+-    <dd>Same thing
+-    <dt><pre>cvs update &lt file name &gt</pre>
+-    <dd>Same thing but for just the named file(s)/directory(s).
+-    <dt><pre>cvs commit</pre>
+-    <dd>Will check in all your work.
+-    <dt><pre>cvs add &lt file name &gt</pre>
+-
+-    <dd>Adds the named file/directory into CVS
+-    <dt><pre>cvs remove &lt file name &gt</pre>
+-    <dd>Removes the named file/directory from the upstream repository.
+-    <dt><pre>cvs rm &lt file name &gt</pre>
+-    <dd>Same thing
+-    <dt><pre>cvs log &lt file name &gt</pre>
+-</dl>
+-
+-
+-<!--#include file="footer.html" -->
+-
+diff -Nur busybox-1.00/docs/busybox.net/cvs_write.html busybox/docs/busybox.net/cvs_write.html
+--- busybox-1.00/docs/busybox.net/cvs_write.html       2004-09-08 22:13:05.000000000 +0200
++++ busybox/docs/busybox.net/cvs_write.html    1970-01-01 01:00:00.000000000 +0100
+@@ -1,32 +0,0 @@
+-<!--#include file="header.html" -->
+-
+-
+-<h3>CVS Read/Write Access</h3>
+-
+-If you want to be able to commit things to CVS, first contribute some
+-stuff to show you are serious.  Then, very nicely ask
+-<a href="mailto:andersen@codepoet.org">Erik Andersen</a> if he will set you up with
+-an account.  To access CVS, you will want to add the following to set up your environment:
+-<pre>
+-$ export CVS_RSH=/usr/bin/ssh
+-$ export CVSROOT='username@cvs.busybox.net:/var/cvs'</pre>
+-<br>
+-It goes without saying you must change <em>username</em> to your own
+-username...
+-<p>
+-
+-To obtain commit access, you will need to demonstrate you are
+-serious by submitting a few good patches first.  Then, you will need to
+-select a user-name to use when committing stuff, and finally, you will
+-need to send me the username you have selected, an ssh key, and the email
+-address where you prefer email to be sent (I will forward any email sent
+-to you, but not store it).
+-
+-<p>
+-Note that if you would prefer to keep your communications with me
+-private, you can encrypt your email using my
+-<a href="http://www.codepoet.org/andersen/erik/gpg.asc">public key</a>.
+-
+-<!--#include file="footer.html" -->
+-
+-
+diff -Nur busybox-1.00/docs/busybox.net/developer.html busybox/docs/busybox.net/developer.html
+--- busybox-1.00/docs/busybox.net/developer.html       1970-01-01 01:00:00.000000000 +0100
++++ busybox/docs/busybox.net/developer.html    2005-06-04 08:20:06.000000000 +0200
+@@ -0,0 +1,58 @@
++<!--#include file="header.html" -->
++
++
++<h3>Subversion Read/Write Access</h3>
++
++If you want to be able to commit things to Subversion, first contribute some
++stuff to show you are serious.  Then, very nicely ask <a
++href="mailto:andersen@codepoet.org">Erik Andersen</a> if he will set you up
++with an commit access to the Subversion repository.  To access Subversion, you
++will want to add the following to set up your environment:
++
++<p>
++
++To obtain commit access, you will need to demonstrate you are serious by
++submitting a few good patches first.  Then, you will need to select a username
++to use when committing stuff, and finally, you will need to send me the
++username you have selected, an ssh key, and the email address where you prefer
++email to be sent (I will forward any email sent to you, but not store it).
++
++<p>
++
++Note that if you would prefer to keep your communications with me
++private, you can encrypt your email using my
++<a href="http://www.codepoet.org/andersen/erik/gpg.asc">public key</a>.
++
++<p>
++
++Once you are setup with an account, you will need to use your account to
++checkout a copy of BusyBox from Subversion:
++
++<pre>
++svn list svn+ssh://username@svn.uclibc.org/svn/trunk/busybox</pre>
++<br>
++It goes without saying you must change <em>username</em> to your own
++username...
++<p>
++
++You can then enter the newly checked out BusyBox directory, make changes, check
++your changes, diff your changes, revert your changes, and and commit your
++changes usine commands such as:
++
++<pre>
++svn diff
++svn status
++svn revert
++svn commit</pre>
++
++<p>
++
++For additional detail on how to use Subversion, please visit the
++<a href="http://subversion.tigris.org/">the Subversion website</a>.
++You might also want to read online or buy a copy of <a
++href="http://svnbook.red-bean.com/">the Subversion Book</a>...
++
++
++<!--#include file="footer.html" -->
++
++
+diff -Nur busybox-1.00/docs/busybox.net/download.html busybox/docs/busybox.net/download.html
+--- busybox-1.00/docs/busybox.net/download.html        2004-03-15 09:28:29.000000000 +0100
++++ busybox/docs/busybox.net/download.html     2005-06-04 08:20:06.000000000 +0200
+@@ -9,27 +9,18 @@
+ <p>
+ You can also obtain <a href= "downloads/snapshots/">Daily Snapshots</a> of
+-the latest stable, and the latest development CVS source trees.
+-
+-<p>
+-BusyBox now has <b>two</b> CVS trees.  The "busybox-stable" tree
+-contains the older 0.60.x stable series.  The "busybox" tree contains
+-the latest 1.0.0-preX development version of busybox.<br>
++the latest development source tree for those wishing to follow BusyBox development,
++but cannot or do not wish to use Subversion (svn).
+ <ul>
+-      <li> Click here to browse the <a href="/cgi-bin/cvsweb/busybox/">
+-              CVS tree for the 1.0.0-preX development version of BusyBox</a>
+-      </li>
+-
+-      <li>Click here to browse the <a href="/cgi-bin/cvsweb/busybox.stable/">
+-              CVS tree for the stable 0.60.x version of BusyBox</a>.
++      <li> Click here to <a href="/cgi-bin/viewcvs.cgi/trunk/busybox/">browse the source tree</a>.
+       </li>
+-      <li>Anonymous <a href="cvs_anon.html">CVS access</a> is available.
++      <li>Anonymous <a href="subversion.html">Subversion access</a> is available.
+       </li>
+-      <li>For those that are actively contributing there is
+-              even <a href="cvs_write.html">CVS write access</a>.
++      <li>For those that are actively contributing obtaining
++              <a href="developer.html">Subversion read/write access</a> is also possible.
+       </li>
+ </ul>
+diff -Nur busybox-1.00/docs/busybox.net/footer.html busybox/docs/busybox.net/footer.html
+--- busybox-1.00/docs/busybox.net/footer.html  2004-03-15 09:28:29.000000000 +0100
++++ busybox/docs/busybox.net/footer.html       2005-06-04 08:20:06.000000000 +0200
+@@ -7,14 +7,34 @@
+ <hr />
+-    <p>
+-    <font face="arial, helvetica, sans-serif" size="-1">
+-      <a HREF="/copyright.txt">Copyright &copy; 1999-2003 Erik Andersen</a>
+-      <br>
+-      Mail all comments, insults, suggestions and bribes to
+-      <br>
+-      Erik Andersen <A HREF="mailto:andersen@codepoet.org">andersen@codepoet.org</A><BR>
+-    </font>
++
++    <table width="100%">
++      <tr>
++          <td width="60%">
++              <font face="arial, helvetica, sans-serif" size="-1">
++                  <a href="/copyright.txt">Copyright &copy; 1999-2005 Erik Andersen</a>
++                  <br>
++                  Mail all comments, insults, suggestions and bribes to
++                  <br>
++                  Erik Andersen <a href="mailto:andersen@codepoet.org">andersen@codepoet.org</a><br>
++              </font>
++          </td>
++
++          <td>
++              <a href="http://www.vim.org/"><img border=0 width=88 height=31
++              src="images/written.in.vi.png"
++              alt="This site created with the vi editor"></a>
++          </td>
++
++          <td>
++              <a href="http://osuosl.org/"><img border=0 width=114 height=63
++              src="images/osuosl.png"
++              alt="This site is kindly hosted by OSL"></a>
++          </td>
++
++      </TR>
++    </table>
+   </body>
+ </html>
++
+diff -Nur busybox-1.00/docs/busybox.net/header.html busybox/docs/busybox.net/header.html
+--- busybox-1.00/docs/busybox.net/header.html  2004-10-08 12:50:08.000000000 +0200
++++ busybox/docs/busybox.net/header.html       2005-06-04 08:20:06.000000000 +0200
+@@ -48,9 +48,10 @@
+     <br><a href="/lists.html">Mailing Lists</a>
+     <br><a href="/news.html">Latest News</a>
+     <br><a href="/download.html">Download</a>
++    <br><a href="/cgi-bin/viewcvs.cgi/trunk/busybox/">Browse Source</a>
++    <br><a href="/subversion.html">Accessing Source</a>
++    <br><a href="http://bugs.busybox.net/">Bug Tracking</a>
+     <br><a href="/FAQ.html">FAQ</a>
+-    <br><a href="/cvs_anon.html">Accessing CVS</a>
+-    <br><a href="/cgi-bin/cvsweb/busybox/">Browse CVS</a>
+     <br><a href="/docs.html">Documentation</a>
+     <br><a href="/products.html">Products</a>
+     <br><a href="/shame.html">Hall of Shame</a>
+@@ -58,8 +59,11 @@
+     <p><b>Related Sites</b>
+     <br><a href="http://uclibc.org/">uClibc.org</a>
++    <br><a href="http://cxx.uclibc.org/">uClibc++</a>
+     <br><a href="http://udhcp.busybox.net/">udhcp</a>
+-    <br><a href="http://tinylogin.busybox.net/">tinylogin</a>
++    <br><a href="http://buildroot.uclibc.org/">buildroot</a>
++    <br><a href="http://www.scratchbox.org/">Scratchbox</a>
++    <br><a href="http://openembedded.org/">OpenEmbedded</a>
+     <br><a href="http://www.ucdot.org/">uCdot</a>
+     <br><a href="http://www.linuxdevices.com">LinuxDevices</a>
+     <br><a href="http://slashdot.org/">Slashdot</a>
+Files busybox-1.00/docs/busybox.net/images/osuosl.png and busybox/docs/busybox.net/images/osuosl.png differ
+diff -Nur busybox-1.00/docs/busybox.net/lists.html busybox/docs/busybox.net/lists.html
+--- busybox-1.00/docs/busybox.net/lists.html   2004-06-19 08:26:30.000000000 +0200
++++ busybox/docs/busybox.net/lists.html        2005-06-04 08:20:06.000000000 +0200
+@@ -15,7 +15,8 @@
+ wishing to read the complete diff of each and every change to busybox -- not for the
+ faint of heart.  Active developers can subscribe by visiting
+ <a href="http://codepoet.org/mailman/listinfo/busybox-cvs">this page</a>.
+-The CVS server is the only one permtted to post to this list.
++The Subversion server is the only one permtted to post to this list.  And yes,
++this list name uses the word 'cvs' even though we don't use that anymore...
+ <p>
+diff -Nur busybox-1.00/docs/busybox.net/news.html busybox/docs/busybox.net/news.html
+--- busybox-1.00/docs/busybox.net/news.html    2004-10-13 11:42:10.000000000 +0200
++++ busybox/docs/busybox.net/news.html 2005-06-04 08:20:06.000000000 +0200
+@@ -3,6 +3,25 @@
+ <ul>
++  <li><b>13 January 2005 -- Bug and Patch Tracking</b><p>
++
++    Bug reports sometimes get lost when posted to the mailing list.  The
++    developers of BusyBox are busy people, and have only so much they can keep
++    in their brains at a time. In my case, I'm lucky if I can remember my own
++    name, much less a bug report posted last week... To prevent your bug report
++    from getting lost, if you find a bug in BusyBox, please use the 
++    <a href="http://bugs.busybox.net/">shiny new Bug and Patch Tracking System</a>
++    to post all the gory details.
++
++    <p>
++
++    The same applies to patches... Regardless of whether your patch
++    is a bug fix or adds spiffy new features, please post your patch
++    to the Bug and Patch Tracking System to make certain it is
++    properly considered.
++
++
++  <p>
+   <li><b>13 October 2004 -- BusyBox 1.00 released</b><p>
+     When you take a careful look at nearly every embedded Linux device or
+diff -Nur busybox-1.00/docs/busybox.net/oldnews.html busybox/docs/busybox.net/oldnews.html
+--- busybox-1.00/docs/busybox.net/oldnews.html 2004-10-13 11:42:10.000000000 +0200
++++ busybox/docs/busybox.net/oldnews.html      2005-06-04 08:20:06.000000000 +0200
+@@ -888,7 +888,7 @@
+      Also, some exciting infrastructure news!  Busybox now has its own
+      <a href="lists/busybox/">mailing list</a>,
+      publically browsable
+-     <a href="/cgi-bin/cvsweb/busybox/">CVS tree</a>,
++     <a href="/cgi-bin/viewcvs.cgi/trunk/busybox/">CVS tree</a>,
+      anonymous
+      <a href="cvs_anon.html">CVS access</a>, and
+      for those that are actively contributing there is even
+diff -Nur busybox-1.00/docs/busybox.net/products.html busybox/docs/busybox.net/products.html
+--- busybox-1.00/docs/busybox.net/products.html        2004-10-13 11:42:10.000000000 +0200
++++ busybox/docs/busybox.net/products.html     2005-06-04 08:20:06.000000000 +0200
+@@ -13,7 +13,7 @@
+ <ul>
+-<li><a href="/cgi-bin/cvsweb/buildroot/">buildroot</a><br>A configurable
++<li><a href="http://buildroot.uclibc.org/">buildroot</a><br>A configurable
+ means for building your own busybox/uClibc based system systems.
+ <li><a href="http://www.pengutronix.de/software/ptxdist_en.html">PTXdist</a><br>another
+diff -Nur busybox-1.00/docs/busybox.net/subversion.html busybox/docs/busybox.net/subversion.html
+--- busybox-1.00/docs/busybox.net/subversion.html      1970-01-01 01:00:00.000000000 +0100
++++ busybox/docs/busybox.net/subversion.html   2005-06-04 08:20:06.000000000 +0200
+@@ -0,0 +1,38 @@
++<!--#include file="header.html" -->
++
++
++<h3>Anonymous Subversion Access</h3>
++
++We allow anonymous (read-only) Subversion (svn) access to everyone.  To
++grab a copy of the latest version of BusyBox using anonymous svn access is:
++
++<pre>
++svn co svn://busybox.net/trunk/busybox</pre>
++
++
++<p>
++
++If you are not already familiar with using Subversion, I recommend you visit <a
++href="http://subversion.tigris.org/">the Subversion website</a>.  You might
++also want to read online or buy a copy of <a
++href="http://svnbook.red-bean.com/">the Subversion Book</a>.  If you are
++already comfortable with using CVS, you may want to skip ahead to the <a
++href="http://svnbook.red-bean.com/en/1.1/apa.html">Subversion for CVS Users</a>
++part of the Subversion Book.
++
++<p>
++
++Once you've checked out a copy of the source tree, you can update your source
++tree at any time so it is in sync with the latest and greatest by entering your
++BusyBox directory and running the command:
++
++<pre>
++svn update</pre>
++
++Because you've only been granted anonymous access to the tree, you won't be
++able to commit any changes. Changes can be submitted for inclusion by posting
++them to the BusyBox mailing list.  For those that are actively contributing
++<a href="developer.html">Subversion commit access</a> can be made available.
++
++<!--#include file="footer.html" -->
++
+diff -Nur busybox-1.00/docs/busybox.net/tinyutils.html busybox/docs/busybox.net/tinyutils.html
+--- busybox-1.00/docs/busybox.net/tinyutils.html       1970-01-01 01:00:00.000000000 +0100
++++ busybox/docs/busybox.net/tinyutils.html    2005-06-04 08:20:06.000000000 +0200
+@@ -0,0 +1,35 @@
++<!--#include file="header.html" -->
++
++
++<h3>External Tiny Utilities</h3>
++
++This is a list of tiny utilities whose functionality is not provided by 
++busybox.  If you have additional suggestions, please send an e-mail to our 
++dev mailing list.
++
++<br><br>
++
++<table>
++<tr>
++ <th>Feature</th>
++ <th>Utilities</th>
++</tr>
++
++<tr>
++ <td>SSH</td>
++ <td><a href="http://matt.ucc.asn.au/dropbear/">Dropbear</a> has both a sshd and a ssh client.</td>
++</tr>
++
++<tr>
++ <td>SMTP</td>
++ <td><a href="ftp://ftp.debian.org/debian/pool/main/s/ssmtp/">ssmtp</a> is an extremely simple MTA.</td>
++</tr>
++
++<tr>
++ <td>DNS</td>
++ <td><a href="http://www.thekelleys.org.uk/dnsmasq/">dnsmasq</a> is a small forwarding DNS server meant for small environments.</td>
++</tr>
++</table>
++
++<!--#include file="footer.html" -->
++
+diff -Nur busybox-1.00/docs/busybox_footer.pod busybox/docs/busybox_footer.pod
+--- busybox-1.00/docs/busybox_footer.pod       2004-04-25 08:05:14.000000000 +0200
++++ busybox/docs/busybox_footer.pod    2005-06-04 08:20:06.000000000 +0200
+@@ -254,5 +254,5 @@
+ =cut
+-# $Id$
++# $Id$
+diff -Nur busybox-1.00/docs/new-applet-HOWTO.txt busybox/docs/new-applet-HOWTO.txt
+--- busybox-1.00/docs/new-applet-HOWTO.txt     2004-03-15 09:28:26.000000000 +0100
++++ busybox/docs/new-applet-HOWTO.txt  2005-06-04 08:20:06.000000000 +0200
+@@ -52,10 +52,10 @@
+       char mu;
+       if ((fd = open("/dev/random", O_RDONLY)) < 0)
+-              perror_msg_and_die("/dev/random");
++              bb_perror_msg_and_die("/dev/random");
+       if ((n = safe_read(fd, &mu, 1)) < 1)
+-              perror_msg_and_die("/dev/random");
++              bb_perror_msg_and_die("/dev/random");
+       return mu;
+ }
+@@ -137,11 +137,6 @@
+       /* all programs below here are alphabetically "greater than" 'mu' */
+-Finally, add a define for your applet to include/config.h
+-
+-      #undef CONFIG_MU
+-
+-
+ Documentation
+ -------------
+diff -Nur busybox-1.00/e2fsprogs/Config.in busybox/e2fsprogs/Config.in
+--- busybox-1.00/e2fsprogs/Config.in   1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/Config.in        2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,20 @@
++#
++# For a description of the syntax of this configuration file,
++# see scripts/kbuild/config-language.txt.
++#
++
++menu "Linux Ext2 FS Progs"
++
++config CONFIG_CHATTR
++      bool "chattr"
++      default n
++      help
++        chattr changes the file attributes on a second extended file system.
++
++config CONFIG_LSATTR
++      bool "lsattr"
++      default n
++      help
++        lsattr lists the file attributes on a second extended file system.
++
++endmenu
+diff -Nur busybox-1.00/e2fsprogs/Makefile busybox/e2fsprogs/Makefile
+--- busybox-1.00/e2fsprogs/Makefile    1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/Makefile 2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,31 @@
++# Makefile for busybox
++#
++# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++# General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++#
++
++top_srcdir=..
++top_builddir=..
++srcdir=$(top_srcdir)/e2fsprogs
++E2FSPROGS_DIR:=./
++include $(top_builddir)/Rules.mak
++include $(top_builddir)/.config
++include Makefile.in
++all: $(libraries-y)
++-include $(top_builddir)/.depend
++
++clean:
++      rm -f *.o *.a $(AR_TARGET)
+diff -Nur busybox-1.00/e2fsprogs/Makefile.in busybox/e2fsprogs/Makefile.in
+--- busybox-1.00/e2fsprogs/Makefile.in 1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/Makefile.in      2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,44 @@
++# Makefile for busybox
++#
++# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++# General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++#
++
++E2FSPROGS_AR:=e2fsprogs.a
++ifndef $(E2FSPROGS_DIR)
++E2FSPROGS_DIR:=$(top_builddir)/e2fsprogs/
++endif
++srcdir=$(top_srcdir)/e2fsprogs
++
++CFLAGS += -I$(E2FSPROGS_DIR)
++
++E2P_SRC:=fgetsetflags.c fgetsetversion.c pf.c iod.c
++E2P_SRCS:=$(patsubst %,e2p/%, $(E2P_SRC))
++E2P_OBJS=$(patsubst %.c,%.o, $(E2P_SRCS))
++
++E2FSPROGS-:=
++E2FSPROGS-$(CONFIG_CHATTR)      += chattr.o $(E2P_OBJS)
++E2FSPROGS-$(CONFIG_LSATTR)      += lsattr.o $(E2P_OBJS)
++
++libraries-y+=$(E2FSPROGS_DIR)$(E2FSPROGS_AR)
++
++
++$(E2FSPROGS_DIR)$(E2FSPROGS_AR): $(patsubst %,$(E2FSPROGS_DIR)%, $(E2FSPROGS-y))
++      $(AR) -ro $@ $(patsubst %,$(E2FSPROGS_DIR)%, $(E2FSPROGS-y))
++
++$(E2FSPROGS_DIR)%.o: $(srcdir)/%.c
++      $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -DHAVE_ERRNO_H=1 -DHAVE_UNISTD_H=1 \
++              -DHAVE_EXT2_IOCTLS=1 -DHAVE_EXT2_IOCTLS=1 -c -o $@ $<
+diff -Nur busybox-1.00/e2fsprogs/README busybox/e2fsprogs/README
+--- busybox-1.00/e2fsprogs/README      1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/README   2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,3 @@
++This is a pretty straight rip from the e2fsprogs pkg.
++
++See README's in subdirs for specific info.
+diff -Nur busybox-1.00/e2fsprogs/base_device.c busybox/e2fsprogs/base_device.c
+--- busybox-1.00/e2fsprogs/base_device.c       1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/base_device.c    2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,147 @@
++/*
++ * base_device.c
++ *
++ * Return the "base device" given a particular device; this is used to
++ * assure that we only fsck one partition on a particular drive at any
++ * one time.  Otherwise, the disk heads will be seeking all over the
++ * place.  If the base device can not be determined, return NULL.
++ * 
++ * The base_device() function returns an allocated string which must
++ * be freed.
++ * 
++ * Written by Theodore Ts'o, <tytso@mit.edu>
++ * 
++ * Copyright (C) 2000 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++#include <stdio.h>
++#include <unistd.h>
++#include <stdlib.h>
++#include <ctype.h>
++#include <string.h>
++
++#include "busybox.h"
++
++#ifdef CONFIG_FEATURE_DEVFS
++/*
++ * Required for the uber-silly devfs /dev/ide/host1/bus2/target3/lun3
++ * pathames.
++ */
++static const char *devfs_hier[] = {
++      "host", "bus", "target", "lun", 0
++};
++#endif
++
++char *base_device(const char *device)
++{
++      char *str, *cp;
++#ifdef CONFIG_FEATURE_DEVFS
++      const char **hier, *disk;
++      int len;
++#endif
++
++      cp = str = bb_xstrdup(device);
++
++      /* Skip over /dev/; if it's not present, give up. */
++      if (strncmp(cp, "/dev/", 5) != 0)
++              goto errout;
++      cp += 5;
++
++#if 0 /* this is for old stuff no one uses anymore ? */
++      /* Skip over /dev/dsk/... */
++      if (strncmp(cp, "dsk/", 4) == 0)
++              cp += 4;
++#endif
++
++      /*
++       * For md devices, we treat them all as if they were all
++       * on one disk, since we don't know how to parallelize them.
++       */
++      if (cp[0] == 'm' && cp[1] == 'd') {
++              *(cp+2) = 0;
++              return str;
++      }
++
++      /* Handle DAC 960 devices */
++      if (strncmp(cp, "rd/", 3) == 0) {
++              cp += 3;
++              if (cp[0] != 'c' || cp[2] != 'd' ||
++                  !isdigit(cp[1]) || !isdigit(cp[3]))
++                      goto errout;
++              *(cp+4) = 0;
++              return str;
++      }
++
++      /* Now let's handle /dev/hd* and /dev/sd* devices.... */
++      if ((cp[0] == 'h' || cp[0] == 's') && (cp[1] == 'd')) {
++              cp += 2;
++              /* If there's a single number after /dev/hd, skip it */
++              if (isdigit(*cp))
++                      cp++;
++              /* What follows must be an alpha char, or give up */
++              if (!isalpha(*cp))
++                      goto errout;
++              *(cp + 1) = 0;
++              return str;
++      }
++
++#ifdef CONFIG_FEATURE_DEVFS
++      /* Now let's handle devfs (ugh) names */
++      len = 0;
++      if (strncmp(cp, "ide/", 4) == 0)
++              len = 4;
++      if (strncmp(cp, "scsi/", 5) == 0)
++              len = 5;
++      if (len) {
++              cp += len;
++              /*
++               * Now we proceed down the expected devfs hierarchy.
++               * i.e., .../host1/bus2/target3/lun4/...
++               * If we don't find the expected token, followed by
++               * some number of digits at each level, abort.
++               */
++              for (hier = devfs_hier; *hier; hier++) {
++                      len = strlen(*hier);
++                      if (strncmp(cp, *hier, len) != 0)
++                              goto errout;
++                      cp += len;
++                      while (*cp != '/' && *cp != 0) {
++                              if (!isdigit(*cp))
++                                      goto errout;
++                              cp++;
++                      }
++                      cp++;
++              }
++              *(cp - 1) = 0;
++              return str;
++      }
++
++      /* Now handle devfs /dev/disc or /dev/disk names */
++      disk = 0;
++      if (strncmp(cp, "discs/", 6) == 0)
++              disk = "disc";
++      else if (strncmp(cp, "disks/", 6) == 0)
++              disk = "disk";
++      if (disk) {
++              cp += 6;
++              if (strncmp(cp, disk, 4) != 0)
++                      goto errout;
++              cp += 4;
++              while (*cp != '/' && *cp != 0) {
++                      if (!isdigit(*cp))
++                              goto errout;
++                      cp++;
++              }
++              *cp = 0;
++              return str;
++      }
++#endif
++
++errout:
++      free(str);
++      return NULL;
++}
+diff -Nur busybox-1.00/e2fsprogs/blkid/blkid.h busybox/e2fsprogs/blkid/blkid.h
+--- busybox-1.00/e2fsprogs/blkid/blkid.h       1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/blkid/blkid.h    2005-06-04 08:20:15.000000000 +0200
+@@ -0,0 +1,105 @@
++/*
++ * blkid.h - Interface for libblkid, a library to identify block devices
++ *
++ * Copyright (C) 2001 Andreas Dilger
++ * Copyright (C) 2003 Theodore Ts'o
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the
++ * GNU Lesser General Public License.
++ * %End-Header%
++ */
++
++#ifndef _BLKID_BLKID_H
++#define _BLKID_BLKID_H
++
++#include <sys/types.h>
++#include <linux/types.h>
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++#define BLKID_VERSION "1.0.0"
++#define BLKID_DATE    "12-Feb-2003"
++
++typedef struct blkid_struct_dev *blkid_dev;
++typedef struct blkid_struct_cache *blkid_cache;
++typedef __s64 blkid_loff_t;
++
++typedef struct blkid_struct_tag_iterate *blkid_tag_iterate;
++typedef struct blkid_struct_dev_iterate *blkid_dev_iterate;
++
++/*
++ * Flags for blkid_get_dev
++ *
++ * BLKID_DEV_CREATE   Create an empty device structure if not found
++ *                    in the cache.
++ * BLKID_DEV_VERIFY   Make sure the device structure corresponds
++ *                    with reality.
++ * BLKID_DEV_FIND     Just look up a device entry, and return NULL
++ *                    if it is not found.
++ * BLKID_DEV_NORMAL   Get a valid device structure, either from the
++ *                    cache or by probing the device.
++ */
++#define BLKID_DEV_FIND                0x0000
++#define BLKID_DEV_CREATE      0x0001
++#define BLKID_DEV_VERIFY      0x0002
++#define BLKID_DEV_NORMAL      (BLKID_DEV_CREATE | BLKID_DEV_VERIFY)
++
++/* cache.c */
++extern void blkid_put_cache(blkid_cache cache);
++extern int blkid_get_cache(blkid_cache *cache, const char *filename);
++
++/* dev.c */
++extern const char *blkid_dev_devname(blkid_dev dev);
++
++extern blkid_dev_iterate blkid_dev_iterate_begin(blkid_cache cache);
++extern int blkid_dev_next(blkid_dev_iterate iterate, blkid_dev *dev);
++extern void blkid_dev_iterate_end(blkid_dev_iterate iterate);
++
++/* devno.c */
++extern char *blkid_devno_to_devname(dev_t devno);
++
++/* devname.c */
++extern int blkid_probe_all(blkid_cache cache);
++extern blkid_dev blkid_get_dev(blkid_cache cache, const char *devname,
++                             int flags);
++
++/* getsize.c */
++extern blkid_loff_t blkid_get_dev_size(int fd);
++
++/* probe.c */
++int blkid_known_fstype(const char *fstype);
++extern blkid_dev blkid_verify(blkid_cache cache, blkid_dev dev);
++
++/* read.c */
++
++/* resolve.c */
++extern char *blkid_get_tag_value(blkid_cache cache, const char *tagname,
++                                     const char *devname);
++extern char *blkid_get_devname(blkid_cache cache, const char *token,
++                             const char *value);
++
++/* tag.c */
++extern blkid_tag_iterate blkid_tag_iterate_begin(blkid_dev dev);
++extern int blkid_tag_next(blkid_tag_iterate iterate,
++                            const char **type, const char **value);
++extern void blkid_tag_iterate_end(blkid_tag_iterate iterate);
++
++extern blkid_dev blkid_find_dev_with_tag(blkid_cache cache,
++                                       const char *type,
++                                       const char *value);
++extern int blkid_parse_tag_string(const char *token, char **ret_type,
++                                char **ret_val);
++
++/* version.c */
++extern int blkid_parse_version_string(const char *ver_string);
++extern int blkid_get_library_version(const char **ver_string,
++                                   const char **date_string);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _BLKID_BLKID_H */
+diff -Nur busybox-1.00/e2fsprogs/blkid/blkidP.h busybox/e2fsprogs/blkid/blkidP.h
+--- busybox-1.00/e2fsprogs/blkid/blkidP.h      1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/blkid/blkidP.h   2005-06-04 08:20:15.000000000 +0200
+@@ -0,0 +1,239 @@
++/*
++ * blkidP.h - Internal interfaces for libblkid
++ *
++ * Copyright (C) 2001 Andreas Dilger
++ * Copyright (C) 2003 Theodore Ts'o
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the
++ * GNU Lesser General Public License.
++ * %End-Header%
++ */
++
++#ifndef _BLKID_BLKIDP_H
++#define _BLKID_BLKIDP_H
++
++#include <sys/types.h>
++#include <stdio.h>
++
++#include <blkid/blkid.h>
++
++#include <blkid/list.h>
++
++#ifdef __GNUC__
++#define __BLKID_ATTR(x) __attribute__(x)
++#else
++#define __BLKID_ATTR(x)
++#endif
++
++
++/*
++ * This describes the attributes of a specific device.
++ * We can traverse all of the tags by bid_tags (linking to the tag bit_names).
++ * The bid_label and bid_uuid fields are shortcuts to the LABEL and UUID tag
++ * values, if they exist.
++ */
++struct blkid_struct_dev
++{
++      struct list_head        bid_devs;       /* All devices in the cache */
++      struct list_head        bid_tags;       /* All tags for this device */
++      blkid_cache             bid_cache;      /* Dev belongs to this cache */
++      char                    *bid_name;      /* Device inode pathname */
++      char                    *bid_type;      /* Preferred device TYPE */
++      int                     bid_pri;        /* Device priority */
++      dev_t                   bid_devno;      /* Device major/minor number */
++      time_t                  bid_time;       /* Last update time of device */
++      unsigned int            bid_flags;      /* Device status bitflags */
++      char                    *bid_label;     /* Shortcut to device LABEL */
++      char                    *bid_uuid;      /* Shortcut to binary UUID */
++};
++
++#define BLKID_BID_FL_VERIFIED 0x0001  /* Device data validated from disk */
++#define BLKID_BID_FL_INVALID  0x0004  /* Device is invalid */
++
++/*
++ * Each tag defines a NAME=value pair for a particular device.  The tags
++ * are linked via bit_names for a single device, so that traversing the
++ * names list will get you a list of all tags associated with a device.
++ * They are also linked via bit_values for all devices, so one can easily
++ * search all tags with a given NAME for a specific value.
++ */
++struct blkid_struct_tag
++{
++      struct list_head        bit_tags;       /* All tags for this device */
++      struct list_head        bit_names;      /* All tags with given NAME */
++      char                    *bit_name;      /* NAME of tag (shared) */
++      char                    *bit_val;       /* value of tag */
++      blkid_dev               bit_dev;        /* pointer to device */
++};
++typedef struct blkid_struct_tag *blkid_tag;
++
++/*
++ * Minimum number of seconds between device probes, even when reading
++ * from the cache.  This is to avoid re-probing all devices which were
++ * just probed by another program that does not share the cache.
++ */
++#define BLKID_PROBE_MIN               2
++
++/*
++ * Time in seconds an entry remains verified in the in-memory cache
++ * before being reverified (in case of long-running processes that
++ * keep a cache in memory and continue to use it for a long time).
++ */
++#define BLKID_PROBE_INTERVAL  200
++
++/* This describes an entire blkid cache file and probed devices.
++ * We can traverse all of the found devices via bic_list.
++ * We can traverse all of the tag types by bic_tags, which hold empty tags
++ * for each tag type.  Those tags can be used as list_heads for iterating
++ * through all devices with a specific tag type (e.g. LABEL).
++ */
++struct blkid_struct_cache
++{
++      struct list_head        bic_devs;       /* List head of all devices */
++      struct list_head        bic_tags;       /* List head of all tag types */
++      time_t                  bic_time;       /* Last probe time */
++      time_t                  bic_ftime;      /* Mod time of the cachefile */
++      unsigned int            bic_flags;      /* Status flags of the cache */
++      char                    *bic_filename;  /* filename of cache */
++};
++
++#define BLKID_BIC_FL_PROBED   0x0002  /* We probed /proc/partition devices */
++#define BLKID_BIC_FL_CHANGED  0x0004  /* Cache has changed from disk */
++
++extern char *blkid_strdup(const char *s);
++extern char *blkid_strndup(const char *s, const int length);
++
++#define BLKID_CACHE_FILE "/etc/blkid.tab"
++extern const char *blkid_devdirs[];
++
++#define BLKID_ERR_IO   5
++#define BLKID_ERR_PROC         9
++#define BLKID_ERR_MEM 12
++#define BLKID_ERR_CACHE       14
++#define BLKID_ERR_DEV 19
++#define BLKID_ERR_PARAM       22
++#define BLKID_ERR_BIG 27
++
++/*
++ * Priority settings for different types of devices
++ */
++#define BLKID_PRI_EVMS        30
++#define BLKID_PRI_LVM 20
++#define BLKID_PRI_MD  10
++
++#if defined(TEST_PROGRAM) && !defined(CONFIG_BLKID_DEBUG)
++#define CONFIG_BLKID_DEBUG
++#endif
++
++#define DEBUG_CACHE   0x0001
++#define DEBUG_DUMP    0x0002
++#define DEBUG_DEV     0x0004
++#define DEBUG_DEVNAME 0x0008
++#define DEBUG_DEVNO   0x0010
++#define DEBUG_PROBE   0x0020
++#define DEBUG_READ    0x0040
++#define DEBUG_RESOLVE 0x0080
++#define DEBUG_SAVE    0x0100
++#define DEBUG_TAG     0x0200
++#define DEBUG_INIT    0x8000
++#define DEBUG_ALL     0xFFFF
++
++#ifdef CONFIG_BLKID_DEBUG
++#include <stdio.h>
++extern int    blkid_debug_mask;
++#define DBG(m,x)      if ((m) & blkid_debug_mask) x;
++#else
++#define DBG(m,x)
++#endif
++
++#ifdef CONFIG_BLKID_DEBUG
++static inline void DEB_DUMP_TAG(int mask, blkid_tag tag)
++{
++      if (!(mask & blkid_debug_mask))
++              return;
++      
++      if (!tag) {
++              printf("    tag: NULL\n");
++              return;
++      }
++
++      printf("    tag: %s=\"%s\"\n", tag->bit_name, tag->bit_val);
++}
++
++static inline void DEB_DUMP_DEV(int mask, blkid_dev dev)
++{
++      struct list_head *p;
++
++      if (!(mask & blkid_debug_mask))
++              return;
++      
++      if (!dev) {
++              printf("  dev: NULL\n");
++              return;
++      }
++
++      printf("  dev: name = %s\n", dev->bid_name);
++      printf("  dev: DEVNO=\"0x%0Lx\"\n", dev->bid_devno);
++      printf("  dev: TIME=\"%lu\"\n", dev->bid_time);
++      printf("  dev: PRI=\"%d\"\n", dev->bid_pri);
++      printf("  dev: flags = 0x%08X\n", dev->bid_flags);
++
++      list_for_each(p, &dev->bid_tags) {
++              blkid_tag tag = list_entry(p, struct blkid_struct_tag, bit_tags);
++              DEB_DUMP_TAG(mask, tag);
++      }
++      printf("\n");
++}
++
++static inline void DEB_DUMP_CACHE(int mask, blkid_cache cache)
++{
++      struct list_head *p;
++
++      if (!cache || !(mask & blkid_debug_mask)) {
++              printf("cache: NULL\n");
++              return;
++      }
++
++      printf("cache: time = %lu\n", cache->bic_time);
++      printf("cache: flags = 0x%08X\n", cache->bic_flags);
++
++      list_for_each(p, &cache->bic_devs) {
++              blkid_dev dev = list_entry(p, struct blkid_struct_dev, bid_devs);
++              DEB_DUMP_DEV(mask, dev);
++      }
++}
++#else
++#define DEB_DUMP_TAG(mask, tag) do {} while (0)
++#define DEB_DUMP_DEV(mask, dev) do {} while (0)
++#define DEB_DUMP_CACHE(mask, cache) do {} while (0)
++#endif
++
++/* lseek.c */
++extern blkid_loff_t blkid_llseek(int fd, blkid_loff_t offset, int whence);
++
++/* read.c */
++extern void blkid_read_cache(blkid_cache cache);
++
++/* save.c */
++extern int blkid_flush_cache(blkid_cache cache);
++
++/*
++ * Functions to create and find a specific tag type: tag.c
++ */
++extern void blkid_free_tag(blkid_tag tag);
++extern blkid_tag blkid_find_tag_dev(blkid_dev dev, const char *type);
++extern int blkid_set_tag(blkid_dev dev, const char *name,
++                       const char *value, const int vlength);
++
++/*
++ * Functions to create and find a specific tag type: dev.c
++ */
++extern blkid_dev blkid_new_dev(void);
++extern void blkid_free_dev(blkid_dev dev);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _BLKID_BLKIDP_H */
+diff -Nur busybox-1.00/e2fsprogs/blkid/cache.c busybox/e2fsprogs/blkid/cache.c
+--- busybox-1.00/e2fsprogs/blkid/cache.c       1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/blkid/cache.c    2005-06-04 08:20:15.000000000 +0200
+@@ -0,0 +1,126 @@
++/*
++ * cache.c - allocation/initialization/free routines for cache
++ *
++ * Copyright (C) 2001 Andreas Dilger
++ * Copyright (C) 2003 Theodore Ts'o
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the
++ * GNU Lesser General Public License.
++ * %End-Header%
++ */
++
++#include <stdlib.h>
++#include <string.h>
++#include <unistd.h>
++#include "blkidP.h"
++
++int blkid_debug_mask = 0;
++
++int blkid_get_cache(blkid_cache *ret_cache, const char *filename)
++{
++      blkid_cache cache;
++
++#ifdef CONFIG_BLKID_DEBUG
++      if (!(blkid_debug_mask & DEBUG_INIT)) {
++              char *dstr = getenv("BLKID_DEBUG");
++
++              if (dstr)
++                      blkid_debug_mask = strtoul(dstr, 0, 0);
++              blkid_debug_mask |= DEBUG_INIT;
++      }
++#endif
++
++      DBG(DEBUG_CACHE, printf("creating blkid cache (using %s)\n",
++                              filename ? filename : "default cache"));
++
++      if (!(cache = (blkid_cache) calloc(1, sizeof(struct blkid_struct_cache))))
++              return -BLKID_ERR_MEM;
++
++      INIT_LIST_HEAD(&cache->bic_devs);
++      INIT_LIST_HEAD(&cache->bic_tags);
++
++      if (filename && !strlen(filename))
++              filename = 0;
++      if (!filename && (getuid() == geteuid()))
++              filename = getenv("BLKID_FILE");
++      if (!filename)
++              filename = BLKID_CACHE_FILE;
++      cache->bic_filename = blkid_strdup(filename);
++      
++      blkid_read_cache(cache);
++      
++      *ret_cache = cache;
++      return 0;
++}
++
++void blkid_put_cache(blkid_cache cache)
++{
++      if (!cache)
++              return;
++
++      (void) blkid_flush_cache(cache);
++
++      DBG(DEBUG_CACHE, printf("freeing cache struct\n"));
++      
++      /* DEB_DUMP_CACHE(cache); */
++
++      while (!list_empty(&cache->bic_devs)) {
++              blkid_dev dev = list_entry(cache->bic_devs.next,
++                                         struct blkid_struct_dev,
++                                          bid_devs);
++              blkid_free_dev(dev);
++      }
++
++      while (!list_empty(&cache->bic_tags)) {
++              blkid_tag tag = list_entry(cache->bic_tags.next,
++                                         struct blkid_struct_tag,
++                                         bit_tags);
++
++              while (!list_empty(&tag->bit_names)) {
++                      blkid_tag bad = list_entry(tag->bit_names.next,
++                                                 struct blkid_struct_tag, 
++                                                 bit_names);
++
++                      DBG(DEBUG_CACHE, printf("warning: unfreed tag %s=%s\n",
++                                              bad->bit_name, bad->bit_val));
++                      blkid_free_tag(bad);
++              }
++              blkid_free_tag(tag);
++      }
++      if (cache->bic_filename)
++              free(cache->bic_filename);
++      
++      free(cache);
++}
++
++#ifdef TEST_PROGRAM
++int main(int argc, char** argv)
++{
++      blkid_cache cache = NULL;
++      int ret;
++
++      blkid_debug_mask = DEBUG_ALL;
++      if ((argc > 2)) {
++              fprintf(stderr, "Usage: %s [filename] \n", argv[0]);
++              exit(1);
++      }
++
++      if ((ret = blkid_get_cache(&cache, argv[1])) < 0) {
++              fprintf(stderr, "error %d parsing cache file %s\n", ret,
++                      argv[1] ? argv[1] : BLKID_CACHE_FILE);
++              exit(1);
++      }
++      if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) {
++              fprintf(stderr, "%s: error creating cache (%d)\n",
++                      argv[0], ret);
++              exit(1);
++      }
++      if ((ret = blkid_probe_all(cache) < 0))
++              fprintf(stderr, "error probing devices\n");
++
++      blkid_put_cache(cache);
++
++      return ret;
++}
++#endif
+diff -Nur busybox-1.00/e2fsprogs/blkid/dev.c busybox/e2fsprogs/blkid/dev.c
+--- busybox-1.00/e2fsprogs/blkid/dev.c 1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/blkid/dev.c      2005-06-04 08:20:15.000000000 +0200
+@@ -0,0 +1,118 @@
++/*
++ * dev.c - allocation/initialization/free routines for dev
++ *
++ * Copyright (C) 2001 Andreas Dilger
++ * Copyright (C) 2003 Theodore Ts'o
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the
++ * GNU Lesser General Public License.
++ * %End-Header%
++ */
++
++#include <stdlib.h>
++#include <string.h>
++
++#include "blkidP.h"
++
++blkid_dev blkid_new_dev(void)
++{
++      blkid_dev dev;
++
++      if (!(dev = (blkid_dev) calloc(1, sizeof(struct blkid_struct_dev))))
++              return NULL;
++
++      INIT_LIST_HEAD(&dev->bid_devs);
++      INIT_LIST_HEAD(&dev->bid_tags);
++
++      return dev;
++}
++
++void blkid_free_dev(blkid_dev dev)
++{
++      if (!dev)
++              return;
++
++      DBG(DEBUG_DEV,
++          printf("  freeing dev %s (%s)\n", dev->bid_name, dev->bid_type));
++      DEB_DUMP_DEV(DEBUG_DEV, dev);
++
++      list_del(&dev->bid_devs);
++      while (!list_empty(&dev->bid_tags)) {
++              blkid_tag tag = list_entry(dev->bid_tags.next,
++                                         struct blkid_struct_tag,
++                                         bit_tags);
++              blkid_free_tag(tag);
++      }
++      if (dev->bid_name)
++              free(dev->bid_name);
++      free(dev);
++}
++
++/*
++ * Given a blkid device, return its name
++ */
++extern const char *blkid_dev_devname(blkid_dev dev)
++{
++      return dev->bid_name;
++}
++
++/*
++ * dev iteration routines for the public libblkid interface.
++ *
++ * These routines do not expose the list.h implementation, which are a
++ * contamination of the namespace, and which force us to reveal far, far
++ * too much of our internal implemenation.  I'm not convinced I want
++ * to keep list.h in the long term, anyway.  It's fine for kernel
++ * programming, but performance is not the #1 priority for this
++ * library, and I really don't like the tradeoff of type-safety for
++ * performance for this application.  [tytso:20030125.2007EST]
++ */
++
++/*
++ * This series of functions iterate over all devices in a blkid cache
++ */
++#define DEV_ITERATE_MAGIC     0x01a5284c
++      
++struct blkid_struct_dev_iterate {
++      int                     magic;
++      blkid_cache             cache;
++      struct list_head        *p;
++};
++
++extern blkid_dev_iterate blkid_dev_iterate_begin(blkid_cache cache)
++{
++      blkid_dev_iterate       iter;
++
++      iter = malloc(sizeof(struct blkid_struct_dev_iterate));
++      if (iter) {
++              iter->magic = DEV_ITERATE_MAGIC;
++              iter->cache = cache;
++              iter->p = cache->bic_devs.next;
++      }
++      return (iter);
++}
++
++/*
++ * Return 0 on success, -1 on error
++ */
++extern int blkid_dev_next(blkid_dev_iterate iter,
++                        blkid_dev *dev)
++{
++      *dev = 0;
++      if (!iter || iter->magic != DEV_ITERATE_MAGIC ||
++          iter->p == &iter->cache->bic_devs)
++              return -1;
++      *dev = list_entry(iter->p, struct blkid_struct_dev, bid_devs);
++      iter->p = iter->p->next;
++      return 0;
++}
++
++extern void blkid_dev_iterate_end(blkid_dev_iterate iter)
++{
++      if (!iter || iter->magic != DEV_ITERATE_MAGIC)
++              return;
++      iter->magic = 0;
++      free(iter);
++}
++
+diff -Nur busybox-1.00/e2fsprogs/blkid/devname.c busybox/e2fsprogs/blkid/devname.c
+--- busybox-1.00/e2fsprogs/blkid/devname.c     1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/blkid/devname.c  2005-06-04 08:20:15.000000000 +0200
+@@ -0,0 +1,376 @@
++/*
++ * devname.c - get a dev by its device inode name
++ *
++ * Copyright (C) Andries Brouwer
++ * Copyright (C) 1999, 2000, 2001, 2002, 2003 Theodore Ts'o
++ * Copyright (C) 2001 Andreas Dilger
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the
++ * GNU Lesser General Public License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <stdlib.h>
++#include <string.h>
++#include <ctype.h>
++#if HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++#if HAVE_SYS_STAT_H
++#include <sys/stat.h>
++#endif
++#if HAVE_ERRNO_H
++#include <errno.h>
++#endif
++#if HAVE_SYS_MKDEV_H
++#include <sys/mkdev.h>
++#endif
++#include <time.h>
++
++#include "blkidP.h"
++
++/*
++ * Find a dev struct in the cache by device name, if available.
++ *
++ * If there is no entry with the specified device name, and the create
++ * flag is set, then create an empty device entry.
++ */
++blkid_dev blkid_get_dev(blkid_cache cache, const char *devname, int flags)
++{
++      blkid_dev dev = NULL, tmp;
++      struct list_head *p;
++
++      if (!cache || !devname)
++              return NULL;
++
++      list_for_each(p, &cache->bic_devs) {
++              tmp = list_entry(p, struct blkid_struct_dev, bid_devs);
++              if (strcmp(tmp->bid_name, devname))
++                      continue;
++
++              DBG(DEBUG_DEVNAME, 
++                  printf("found devname %s in cache\n", tmp->bid_name));
++              dev = tmp;
++              break;
++      }
++
++      if (!dev && (flags & BLKID_DEV_CREATE)) {
++              dev = blkid_new_dev();
++              if (!dev)
++                      return NULL;
++              dev->bid_name = blkid_strdup(devname);
++              dev->bid_cache = cache;
++              list_add_tail(&dev->bid_devs, &cache->bic_devs);
++              cache->bic_flags |= BLKID_BIC_FL_CHANGED;
++      }
++
++      if (flags & BLKID_DEV_VERIFY)
++              dev = blkid_verify(cache, dev);
++      return dev;
++}
++
++/*
++ * Probe a single block device to add to the device cache.
++ */
++static void probe_one(blkid_cache cache, const char *ptname,
++                    dev_t devno, int pri)
++{
++      blkid_dev dev = NULL;
++      struct list_head *p;
++      const char **dir;
++      char *devname = NULL;
++
++      /* See if we already have this device number in the cache. */
++      list_for_each(p, &cache->bic_devs) {
++              blkid_dev tmp = list_entry(p, struct blkid_struct_dev,
++                                         bid_devs);
++              if (tmp->bid_devno == devno) {
++                      dev = blkid_verify(cache, tmp);
++                      break;
++              }
++      }
++      if (dev && dev->bid_devno == devno)
++              goto set_pri;
++
++      /*
++       * Take a quick look at /dev/ptname for the device number.  We check
++       * all of the likely device directories.  If we don't find it, or if
++       * the stat information doesn't check out, use blkid_devno_to_devname()
++       * to find it via an exhaustive search for the device major/minor.
++       */
++      for (dir = blkid_devdirs; *dir; dir++) {
++              struct stat st;
++              char device[256];
++
++              sprintf(device, "%s/%s", *dir, ptname);
++              if ((dev = blkid_get_dev(cache, device, BLKID_DEV_FIND)) &&
++                  dev->bid_devno == devno)
++                      goto set_pri;
++
++              if (stat(device, &st) == 0 && S_ISBLK(st.st_mode) && 
++                  st.st_rdev == devno) {
++                      devname = blkid_strdup(device);
++                      break;
++              }
++      }
++      if (!devname) {
++              devname = blkid_devno_to_devname(devno);
++              if (!devname)
++                      return;
++      }
++      dev = blkid_get_dev(cache, devname, BLKID_DEV_NORMAL);
++      free(devname);
++
++set_pri:
++      if (!pri && !strncmp(ptname, "md", 2))
++              pri = BLKID_PRI_MD;
++      if (dev)
++              dev->bid_pri = pri;
++      return;
++}
++
++#define PROC_PARTITIONS "/proc/partitions"
++#define VG_DIR                "/proc/lvm/VGs"
++
++/*
++ * This function initializes the UUID cache with devices from the LVM
++ * proc hierarchy.  We currently depend on the names of the LVM
++ * hierarchy giving us the device structure in /dev.  (XXX is this a
++ * safe thing to do?)
++ */
++#ifdef VG_DIR
++#include <dirent.h>
++static dev_t lvm_get_devno(const char *lvm_device)
++{
++      FILE *lvf;
++      char buf[1024];
++      int ma, mi;
++      dev_t ret = 0;
++
++      DBG(DEBUG_DEVNAME, printf("opening %s\n", lvm_device));
++      if ((lvf = fopen(lvm_device, "r")) == NULL) {
++              DBG(DEBUG_DEVNAME, printf("%s: (%d) %s\n", lvm_device, errno,
++                                        strerror(errno)));
++              return 0;
++      }
++
++      while (fgets(buf, sizeof(buf), lvf)) {
++              if (sscanf(buf, "device: %d:%d", &ma, &mi) == 2) {
++                      ret = makedev(ma, mi);
++                      break;
++              }
++      }
++      fclose(lvf);
++
++      return ret;
++}
++
++static void lvm_probe_all(blkid_cache cache)
++{
++      DIR             *vg_list;
++      struct dirent   *vg_iter;
++      int             vg_len = strlen(VG_DIR);
++      dev_t           dev;
++
++      if ((vg_list = opendir(VG_DIR)) == NULL)
++              return;
++
++      DBG(DEBUG_DEVNAME, printf("probing LVM devices under %s\n", VG_DIR));
++
++      while ((vg_iter = readdir(vg_list)) != NULL) {
++              DIR             *lv_list;
++              char            *vdirname;
++              char            *vg_name;
++              struct dirent   *lv_iter;
++
++              vg_name = vg_iter->d_name;
++              if (!strcmp(vg_name, ".") || !strcmp(vg_name, ".."))
++                      continue;
++              vdirname = malloc(vg_len + strlen(vg_name) + 8);
++              if (!vdirname)
++                      goto exit;
++              sprintf(vdirname, "%s/%s/LVs", VG_DIR, vg_name);
++
++              lv_list = opendir(vdirname);
++              free(vdirname);
++              if (lv_list == NULL)
++                      continue;
++
++              while ((lv_iter = readdir(lv_list)) != NULL) {
++                      char            *lv_name, *lvm_device;
++
++                      lv_name = lv_iter->d_name;
++                      if (!strcmp(lv_name, ".") || !strcmp(lv_name, ".."))
++                              continue;
++
++                      lvm_device = malloc(vg_len + strlen(vg_name) +
++                                          strlen(lv_name) + 8);
++                      if (!lvm_device) {
++                              closedir(lv_list);
++                              goto exit;
++                      }
++                      sprintf(lvm_device, "%s/%s/LVs/%s", VG_DIR, vg_name,
++                              lv_name);
++                      dev = lvm_get_devno(lvm_device);
++                      sprintf(lvm_device, "%s/%s", vg_name, lv_name);
++                      DBG(DEBUG_DEVNAME, printf("LVM dev %s: devno 0x%04X\n",
++                                                lvm_device,
++                                                (unsigned int) dev));
++                      probe_one(cache, lvm_device, dev, BLKID_PRI_LVM);
++                      free(lvm_device);
++              }
++              closedir(lv_list);
++      }
++exit:
++      closedir(vg_list);
++}
++#endif
++
++#define PROC_EVMS_VOLUMES "/proc/evms/volumes"
++
++static int
++evms_probe_all(blkid_cache cache)
++{
++      char line[100];
++      int ma, mi, sz, num = 0;
++      FILE *procpt;
++      char device[110];
++
++      procpt = fopen(PROC_EVMS_VOLUMES, "r");
++      if (!procpt)
++              return 0;
++      while (fgets(line, sizeof(line), procpt)) {
++              if (sscanf (line, " %d %d %d %*s %*s %[^\n ]",
++                          &ma, &mi, &sz, device) != 4)
++                      continue;
++
++              DBG(DEBUG_DEVNAME, printf("Checking partition %s (%d, %d)\n",
++                                        device, ma, mi));
++
++              probe_one(cache, device, makedev(ma, mi), BLKID_PRI_EVMS);
++              num++;
++      }
++      fclose(procpt);
++      return num;
++}
++
++/*
++ * Read the device data for all available block devices in the system.
++ */
++int blkid_probe_all(blkid_cache cache)
++{
++      FILE *proc;
++      char line[1024];
++      char ptname0[128], ptname1[128], *ptname = 0;
++      char *ptnames[2];
++      dev_t devs[2];
++      int ma, mi;
++      unsigned long long sz;
++      int lens[2] = { 0, 0 };
++      int which = 0, last = 0;
++
++      ptnames[0] = ptname0;
++      ptnames[1] = ptname1;
++
++      if (!cache)
++              return -BLKID_ERR_PARAM;
++
++      if (cache->bic_flags & BLKID_BIC_FL_PROBED &&
++          time(0) - cache->bic_time < BLKID_PROBE_INTERVAL)
++              return 0;
++
++      blkid_read_cache(cache);
++      evms_probe_all(cache);
++#ifdef VG_DIR
++      lvm_probe_all(cache);
++#endif
++
++      proc = fopen(PROC_PARTITIONS, "r");
++      if (!proc)
++              return -BLKID_ERR_PROC;
++
++      while (fgets(line, sizeof(line), proc)) {
++              last = which;
++              which ^= 1;
++              ptname = ptnames[which];
++
++              if (sscanf(line, " %d %d %llu %128[^\n ]",
++                         &ma, &mi, &sz, ptname) != 4)
++                      continue;
++              devs[which] = makedev(ma, mi);
++
++              DBG(DEBUG_DEVNAME, printf("read partition name %s\n", ptname));
++
++              /* Skip whole disk devs unless they have no partitions
++               * If we don't have a partition on this dev, also
++               * check previous dev to see if it didn't have a partn.
++               * heuristic: partition name ends in a digit.
++               *
++               * Skip extended partitions.
++               * heuristic: size is 1
++               *
++               * FIXME: skip /dev/{ida,cciss,rd} whole-disk devs
++               */
++
++              lens[which] = strlen(ptname);
++              if (isdigit(ptname[lens[which] - 1])) {
++                      DBG(DEBUG_DEVNAME,
++                          printf("partition dev %s, devno 0x%04X\n",
++                                 ptname, (unsigned int) devs[which]));
++
++                      if (sz > 1)
++                              probe_one(cache, ptname, devs[which], 0);
++                      lens[which] = 0;
++                      lens[last] = 0;
++              } else if (lens[last] && strncmp(ptnames[last], ptname,
++                                               lens[last])) {
++                      DBG(DEBUG_DEVNAME,
++                          printf("whole dev %s, devno 0x%04X\n",
++                                 ptnames[last], (unsigned int) devs[last]));
++                      probe_one(cache, ptnames[last], devs[last], 0);
++                      lens[last] = 0;
++              }
++      }
++
++      /* Handle the last device if it wasn't partitioned */
++      if (lens[which])
++              probe_one(cache, ptname, devs[which], 0);
++
++      fclose(proc);
++
++      cache->bic_time = time(0);
++      cache->bic_flags |= BLKID_BIC_FL_PROBED;
++      blkid_flush_cache(cache);
++      return 0;
++}
++
++#ifdef TEST_PROGRAM
++int main(int argc, char **argv)
++{
++      blkid_cache cache = NULL;
++      int ret;
++
++      blkid_debug_mask = DEBUG_ALL;
++      if (argc != 1) {
++              fprintf(stderr, "Usage: %s\n"
++                      "Probe all devices and exit\n", argv[0]);
++              exit(1);
++      }
++      if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) {
++              fprintf(stderr, "%s: error creating cache (%d)\n",
++                      argv[0], ret);
++              exit(1);
++      }
++      if (blkid_probe_all(cache) < 0)
++              printf("%s: error probing devices\n", argv[0]);
++
++      blkid_put_cache(cache);
++      return (0);
++}
++#endif
+diff -Nur busybox-1.00/e2fsprogs/blkid/devno.c busybox/e2fsprogs/blkid/devno.c
+--- busybox-1.00/e2fsprogs/blkid/devno.c       1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/blkid/devno.c    2005-06-04 08:20:15.000000000 +0200
+@@ -0,0 +1,233 @@
++/*
++ * devno.c - find a particular device by its device number (major/minor)
++ *
++ * Copyright (C) 2000, 2001, 2003 Theodore Ts'o
++ * Copyright (C) 2001 Andreas Dilger
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the
++ * GNU Lesser General Public License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <stdlib.h>
++#include <string.h>
++#if HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++#if HAVE_SYS_STAT_H
++#include <sys/stat.h>
++#endif
++#include <dirent.h>
++#if HAVE_ERRNO_H
++#include <errno.h>
++#endif
++#if HAVE_SYS_MKDEV_H
++#include <sys/mkdev.h>
++#endif
++
++#include "blkidP.h"
++
++struct dir_list {
++      char    *name;
++      struct dir_list *next;
++};
++
++char *blkid_strndup(const char *s, int length)
++{
++      char *ret;
++
++      if (!s)
++              return NULL;
++
++      if (!length)
++              length = strlen(s);
++
++      ret = malloc(length + 1);
++      if (ret) {
++              strncpy(ret, s, length);
++              ret[length] = '\0';
++      }
++      return ret;
++}
++
++char *blkid_strdup(const char *s)
++{
++      return blkid_strndup(s, 0);
++}
++
++/*
++ * This function adds an entry to the directory list
++ */
++static void add_to_dirlist(const char *name, struct dir_list **list)
++{
++      struct dir_list *dp;
++
++      dp = malloc(sizeof(struct dir_list));
++      if (!dp)
++              return;
++      dp->name = blkid_strdup(name);
++      if (!dp->name) {
++              free(dp);
++              return;
++      }
++      dp->next = *list;
++      *list = dp;
++}
++
++/*
++ * This function frees a directory list
++ */
++static void free_dirlist(struct dir_list **list)
++{
++      struct dir_list *dp, *next;
++
++      for (dp = *list; dp; dp = next) {
++              next = dp->next;
++              free(dp->name);
++              free(dp);
++      }
++      *list = NULL;
++}
++
++static void scan_dir(char *dir_name, dev_t devno, struct dir_list **list,
++                          char **devname)
++{
++      DIR     *dir;
++      struct dirent *dp;
++      char    path[1024];
++      int     dirlen;
++      struct stat st;
++
++      if ((dir = opendir(dir_name)) == NULL)
++              return;
++      dirlen = strlen(dir_name) + 2;
++      while ((dp = readdir(dir)) != 0) {
++              if (dirlen + strlen(dp->d_name) >= sizeof(path))
++                      continue;
++
++              if (dp->d_name[0] == '.' &&
++                  ((dp->d_name[1] == 0) ||
++                   ((dp->d_name[1] == '.') && (dp->d_name[2] == 0))))
++                      continue;
++
++              sprintf(path, "%s/%s", dir_name, dp->d_name);
++              if (stat(path, &st) < 0)
++                      continue;
++
++              if (S_ISDIR(st.st_mode))
++                      add_to_dirlist(path, list);
++              else if (S_ISBLK(st.st_mode) && st.st_rdev == devno) {
++                      *devname = blkid_strdup(path);
++                      DBG(DEBUG_DEVNO,
++                          printf("found 0x%Lx at %s (%p)\n", devno,
++                                 path, *devname));
++                      break;
++              }
++      }
++      closedir(dir);
++      return;
++}
++
++/* Directories where we will try to search for device numbers */
++const char *blkid_devdirs[] = { "/devices", "/devfs", "/dev", NULL };
++
++/*
++ * This function finds the pathname to a block device with a given
++ * device number.  It returns a pointer to allocated memory to the
++ * pathname on success, and NULL on failure.
++ */
++char *blkid_devno_to_devname(dev_t devno)
++{
++      struct dir_list *list = NULL, *new_list = NULL;
++      char *devname = NULL;
++      const char **dir;
++
++      /*
++       * Add the starting directories to search in reverse order of
++       * importance, since we are using a stack...
++       */
++      for (dir = blkid_devdirs; *dir; dir++)
++              add_to_dirlist(*dir, &list);
++
++      while (list) {
++              struct dir_list *current = list;
++
++              list = list->next;
++              DBG(DEBUG_DEVNO, printf("directory %s\n", current->name));
++              scan_dir(current->name, devno, &new_list, &devname);
++              free(current->name);
++              free(current);
++              if (devname)
++                      break;
++              /*
++               * If we're done checking at this level, descend to
++               * the next level of subdirectories. (breadth-first)
++               */
++              if (list == NULL) {
++                      list = new_list;
++                      new_list = NULL;
++              }
++      }
++      free_dirlist(&list);
++      free_dirlist(&new_list);
++
++      if (!devname) {
++              DBG(DEBUG_DEVNO,
++                  printf("blkid: couldn't find devno 0x%04lx\n", 
++                         (unsigned long) devno));
++      } else {
++              DBG(DEBUG_DEVNO,
++                  printf("found devno 0x%04Lx as %s\n", devno, devname));
++      }
++      
++
++      return devname;
++}
++
++#ifdef TEST_PROGRAM
++int main(int argc, char** argv)
++{
++      char    *devname, *tmp;
++      int     major, minor;
++      dev_t   devno;
++      const char *errmsg = "Couldn't parse %s: %s\n";
++
++      blkid_debug_mask = DEBUG_ALL;
++      if ((argc != 2) && (argc != 3)) {
++              fprintf(stderr, "Usage:\t%s device_number\n\t%s major minor\n"
++                      "Resolve a device number to a device name\n",
++                      argv[0], argv[0]);
++              exit(1);
++      }
++      if (argc == 2) {
++              devno = strtoul(argv[1], &tmp, 0);
++              if (*tmp) {
++                      fprintf(stderr, errmsg, "device number", argv[1]);
++                      exit(1);
++              }
++      } else {
++              major = strtoul(argv[1], &tmp, 0);
++              if (*tmp) {
++                      fprintf(stderr, errmsg, "major number", argv[1]);
++                      exit(1);
++              }
++              minor = strtoul(argv[2], &tmp, 0);
++              if (*tmp) {
++                      fprintf(stderr, errmsg, "minor number", argv[2]);
++                      exit(1);
++              }
++              devno = makedev(major, minor);
++      }
++      printf("Looking for device 0x%04Lx\n", devno);
++      devname = blkid_devno_to_devname(devno);
++      if (devname)
++              free(devname);
++      return 0;
++}
++#endif
+diff -Nur busybox-1.00/e2fsprogs/blkid/getsize.c busybox/e2fsprogs/blkid/getsize.c
+--- busybox-1.00/e2fsprogs/blkid/getsize.c     1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/blkid/getsize.c  2005-06-04 08:20:15.000000000 +0200
+@@ -0,0 +1,180 @@
++/*
++ * getsize.c --- get the size of a partition.
++ *
++ * Copyright (C) 1995, 1995 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the
++ * GNU Lesser General Public License.
++ * %End-Header%
++ */
++
++/* include this before sys/queues.h! */
++#include "blkidP.h"
++
++#include <stdio.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#if HAVE_ERRNO_H
++#include <errno.h>
++#endif
++#include <fcntl.h>
++#ifdef HAVE_SYS_IOCTL_H
++#include <sys/ioctl.h>
++#endif
++#ifdef HAVE_LINUX_FD_H
++#include <linux/fd.h>
++#endif
++#ifdef HAVE_SYS_DISKLABEL_H
++#include <sys/disklabel.h>
++#include <sys/stat.h>
++#endif
++#ifdef HAVE_SYS_DISK_H
++#ifdef HAVE_SYS_QUEUE_H
++#include <sys/queue.h> /* for LIST_HEAD */
++#endif
++#include <sys/disk.h>
++#endif
++#ifdef __linux__
++#include <sys/utsname.h>
++#endif
++
++#if defined(__linux__) && defined(_IO) && !defined(BLKGETSIZE)
++#define BLKGETSIZE _IO(0x12,96)       /* return device size */
++#endif
++
++#if defined(__linux__) && defined(_IOR) && !defined(BLKGETSIZE64)
++#define BLKGETSIZE64 _IOR(0x12,114,size_t)    /* return device size in bytes (u64 *arg) */
++#endif
++
++#ifdef APPLE_DARWIN
++#define BLKGETSIZE DKIOCGETBLOCKCOUNT32
++#endif /* APPLE_DARWIN */
++
++static int valid_offset(int fd, blkid_loff_t offset)
++{
++      char ch;
++
++      if (blkid_llseek(fd, offset, 0) < 0)
++              return 0;
++      if (read(fd, &ch, 1) < 1)
++              return 0;
++      return 1;
++}
++
++/*
++ * Returns the number of blocks in a partition
++ */
++blkid_loff_t blkid_get_dev_size(int fd)
++{
++      int valid_blkgetsize64 = 1;
++#ifdef __linux__
++      struct          utsname ut;
++#endif
++      unsigned long long size64;
++      unsigned long size;
++      blkid_loff_t high, low;
++#ifdef FDGETPRM
++      struct floppy_struct this_floppy;
++#endif
++#ifdef HAVE_SYS_DISKLABEL_H
++      int part = -1;
++      struct disklabel lab;
++      struct partition *pp;
++      char ch;
++      struct stat st;
++#endif /* HAVE_SYS_DISKLABEL_H */
++
++#ifdef DKIOCGETBLOCKCOUNT     /* For Apple Darwin */
++      if (ioctl(fd, DKIOCGETBLOCKCOUNT, &size64) >= 0) {
++              if ((sizeof(blkid_loff_t) < sizeof(unsigned long long))
++                  && (size64 << 9 > 0xFFFFFFFF))
++                      return 0; /* EFBIG */
++              return (blkid_loff_t) size64 << 9;
++      }
++#endif
++
++#ifdef BLKGETSIZE64
++#ifdef __linux__
++      if ((uname(&ut) == 0) &&
++          ((ut.release[0] == '2') && (ut.release[1] == '.') &&
++           (ut.release[2] < '6') && (ut.release[3] == '.')))
++              valid_blkgetsize64 = 0;
++#endif
++      if (valid_blkgetsize64 &&
++          ioctl(fd, BLKGETSIZE64, &size64) >= 0) {
++              if ((sizeof(blkid_loff_t) < sizeof(unsigned long long))
++                  && ((size64) > 0xFFFFFFFF))
++                      return 0; /* EFBIG */
++              return size64;
++      }
++#endif
++
++#ifdef BLKGETSIZE
++      if (ioctl(fd, BLKGETSIZE, &size) >= 0)
++              return (blkid_loff_t)size << 9;
++#endif
++
++#ifdef FDGETPRM
++      if (ioctl(fd, FDGETPRM, &this_floppy) >= 0)
++              return (blkid_loff_t)this_floppy.size << 9;
++#endif
++#ifdef HAVE_SYS_DISKLABEL_H
++#if 0
++      /*
++       * This should work in theory but I haven't tested it.  Anyone
++       * on a BSD system want to test this for me?  In the meantime,
++       * binary search mechanism should work just fine.
++       */
++      if ((fstat(fd, &st) >= 0) && S_ISBLK(st.st_mode))
++              part = st.st_rdev & 7;
++      if (part >= 0 && (ioctl(fd, DIOCGDINFO, (char *)&lab) >= 0)) {
++              pp = &lab.d_partitions[part];
++              if (pp->p_size)
++                      return pp->p_size << 9;
++      }
++#endif
++#endif /* HAVE_SYS_DISKLABEL_H */
++
++      /*
++       * OK, we couldn't figure it out by using a specialized ioctl,
++       * which is generally the best way.  So do binary search to
++       * find the size of the partition.
++       */
++      low = 0;
++      for (high = 1024; valid_offset(fd, high); high *= 2)
++              low = high;
++      while (low < high - 1)
++      {
++              const blkid_loff_t mid = (low + high) / 2;
++
++              if (valid_offset(fd, mid))
++                      low = mid;
++              else
++                      high = mid;
++      }
++      return low + 1;
++}
++
++#ifdef TEST_PROGRAM
++int main(int argc, char **argv)
++{
++      blkid_loff_t bytes;
++      int     fd;
++
++      if (argc < 2) {
++              fprintf(stderr, "Usage: %s device\n"
++                      "Determine the size of a device\n", argv[0]);
++              return 1;
++      }
++
++      if ((fd = open(argv[1], O_RDONLY)) < 0)
++              perror(argv[0]);
++
++      bytes = blkid_get_dev_size(fd);
++      printf("Device %s has %Ld 1k blocks.\n", argv[1], bytes >> 10);
++
++      return 0;
++}
++#endif
+diff -Nur busybox-1.00/e2fsprogs/blkid/list.h busybox/e2fsprogs/blkid/list.h
+--- busybox-1.00/e2fsprogs/blkid/list.h        1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/blkid/list.h     2005-06-04 08:20:15.000000000 +0200
+@@ -0,0 +1,179 @@
++#if !defined(_BLKID_LIST_H) && !defined(LIST_HEAD)
++#define _BLKID_LIST_H
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++#ifdef __GNUC__
++#define _INLINE_ static __inline__
++#else                         /* For Watcom C */
++#define _INLINE_ static inline
++#endif
++
++/*
++ * Simple doubly linked list implementation.
++ *
++ * Some of the internal functions ("__xxx") are useful when
++ * manipulating whole lists rather than single entries, as
++ * sometimes we already know the next/prev entries and we can
++ * generate better code by using them directly rather than
++ * using the generic single-entry routines.
++ */
++
++struct list_head {
++      struct list_head *next, *prev;
++};
++
++#define LIST_HEAD_INIT(name) { &(name), &(name) }
++
++#define LIST_HEAD(name) \
++      struct list_head name = LIST_HEAD_INIT(name)
++
++#define INIT_LIST_HEAD(ptr) do { \
++      (ptr)->next = (ptr); (ptr)->prev = (ptr); \
++} while (0)
++
++/*
++ * Insert a new entry between two known consecutive entries.
++ *
++ * This is only for internal list manipulation where we know
++ * the prev/next entries already!
++ */
++_INLINE_ void __list_add(struct list_head * add,
++      struct list_head * prev,
++      struct list_head * next)
++{
++      next->prev = add;
++      add->next = next;
++      add->prev = prev;
++      prev->next = add;
++}
++
++/**
++ * list_add - add a new entry
++ * @add:      new entry to be added
++ * @head:     list head to add it after
++ *
++ * Insert a new entry after the specified head.
++ * This is good for implementing stacks.
++ */
++_INLINE_ void list_add(struct list_head *add, struct list_head *head)
++{
++      __list_add(add, head, head->next);
++}
++
++/**
++ * list_add_tail - add a new entry
++ * @add:      new entry to be added
++ * @head:     list head to add it before
++ *
++ * Insert a new entry before the specified head.
++ * This is useful for implementing queues.
++ */
++_INLINE_ void list_add_tail(struct list_head *add, struct list_head *head)
++{
++      __list_add(add, head->prev, head);
++}
++
++/*
++ * Delete a list entry by making the prev/next entries
++ * point to each other.
++ *
++ * This is only for internal list manipulation where we know
++ * the prev/next entries already!
++ */
++_INLINE_ void __list_del(struct list_head * prev,
++                                struct list_head * next)
++{
++      next->prev = prev;
++      prev->next = next;
++}
++
++/**
++ * list_del - deletes entry from list.
++ * @entry:    the element to delete from the list.
++ *
++ * list_empty() on @entry does not return true after this, @entry is
++ * in an undefined state.
++ */
++_INLINE_ void list_del(struct list_head *entry)
++{
++      __list_del(entry->prev, entry->next);
++}
++
++/**
++ * list_del_init - deletes entry from list and reinitialize it.
++ * @entry:    the element to delete from the list.
++ */
++_INLINE_ void list_del_init(struct list_head *entry)
++{
++      __list_del(entry->prev, entry->next);
++      INIT_LIST_HEAD(entry);
++}
++
++/**
++ * list_empty - tests whether a list is empty
++ * @head:     the list to test.
++ */
++_INLINE_ int list_empty(struct list_head *head)
++{
++      return head->next == head;
++}
++
++/**
++ * list_splice - join two lists
++ * @list:     the new list to add.
++ * @head:     the place to add it in the first list.
++ */
++_INLINE_ void list_splice(struct list_head *list, struct list_head *head)
++{
++      struct list_head *first = list->next;
++
++      if (first != list) {
++              struct list_head *last = list->prev;
++              struct list_head *at = head->next;
++
++              first->prev = head;
++              head->next = first;
++
++              last->next = at;
++              at->prev = last;
++      }
++}
++
++/**
++ * list_entry - get the struct for this entry
++ * @ptr:      the &struct list_head pointer.
++ * @type:     the type of the struct this is embedded in.
++ * @member:   the name of the list_struct within the struct.
++ */
++#define list_entry(ptr, type, member) \
++      ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
++
++/**
++ * list_for_each - iterate over elements in a list
++ * @pos:      the &struct list_head to use as a loop counter.
++ * @head:     the head for your list.
++ */
++#define list_for_each(pos, head) \
++      for (pos = (head)->next; pos != (head); pos = pos->next)
++
++/**
++ * list_for_each_safe - iterate over elements in a list, but don't dereference
++ *                      pos after the body is done (in case it is freed)
++ * @pos:      the &struct list_head to use as a loop counter.
++ * @pnext:    the &struct list_head to use as a pointer to the next item.
++ * @head:     the head for your list (not included in iteration).
++ */
++#define list_for_each_safe(pos, pnext, head) \
++      for (pos = (head)->next, pnext = pos->next; pos != (head); \
++           pos = pnext, pnext = pos->next)
++
++#undef _INLINE_
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _BLKID_LIST_H */
+diff -Nur busybox-1.00/e2fsprogs/blkid/llseek.c busybox/e2fsprogs/blkid/llseek.c
+--- busybox-1.00/e2fsprogs/blkid/llseek.c      1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/blkid/llseek.c   2005-06-04 08:20:15.000000000 +0200
+@@ -0,0 +1,139 @@
++/*
++ * llseek.c -- stub calling the llseek system call
++ *
++ * Copyright (C) 1994, 1995, 1996, 1997 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the
++ * GNU Lesser General Public License.
++ * %End-Header%
++ */
++
++#if HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++
++#if HAVE_ERRNO_H
++#include <errno.h>
++#endif
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#ifdef __MSDOS__
++#include <io.h>
++#endif
++
++#include "blkidP.h"
++
++#ifdef __linux__
++
++#if defined(HAVE_LSEEK64) && defined(HAVE_LSEEK64_PROTOTYPE)
++
++#define my_llseek lseek64
++
++#elif defined(HAVE_LLSEEK)
++#include <syscall.h>
++
++#ifndef HAVE_LLSEEK_PROTOTYPE
++extern long long llseek(int fd, long long offset, int origin);
++#endif
++
++#define my_llseek llseek
++
++#else /* ! HAVE_LLSEEK */
++
++#if defined(__alpha__) || defined(__ia64__)
++
++#define llseek lseek
++
++#else /* !__alpha__ && !__ia64__*/
++
++#include <linux/unistd.h>
++
++#ifndef __NR__llseek
++#define __NR__llseek            140
++#endif
++
++#ifndef __i386__
++static int _llseek(unsigned int, unsigned long, unsigned long,
++                 blkid_loff_t *, unsigned int);
++
++static _syscall5(int, _llseek, unsigned int, fd, unsigned long, offset_high,
++               unsigned long, offset_low, blkid_loff_t *, result,
++               unsigned int, origin)
++#endif
++
++static blkid_loff_t my_llseek(int fd, blkid_loff_t offset, int origin)
++{
++      blkid_loff_t result;
++      int retval;
++
++#ifndef __i386__
++      retval = _llseek(fd, ((unsigned long long) offset) >> 32,
++                       ((unsigned long long)offset) & 0xffffffff,
++                       &result, origin);
++#else
++      retval = syscall(__NR__llseek, fd, ((unsigned long long) offset) >> 32,
++                       ((unsigned long long)offset) & 0xffffffff,
++                       &result, origin);
++#endif
++      return (retval == -1 ? (blkid_loff_t) retval : result);
++}
++
++#endif        /* __alpha__ || __ia64__ */
++
++#endif /* HAVE_LLSEEK */
++
++blkid_loff_t blkid_llseek(int fd, blkid_loff_t offset, int whence)
++{
++      blkid_loff_t result;
++      static int do_compat = 0;
++
++      if ((sizeof(off_t) >= sizeof(blkid_loff_t)) ||
++          (offset < ((blkid_loff_t) 1 << ((sizeof(off_t)*8) -1))))
++              return lseek(fd, (off_t) offset, whence);
++
++      if (do_compat) {
++              errno = EOVERFLOW;
++              return -1;
++      }
++
++      result = my_llseek(fd, offset, whence);
++      if (result == -1 && errno == ENOSYS) {
++              /*
++               * Just in case this code runs on top of an old kernel
++               * which does not support the llseek system call
++               */
++              do_compat++;
++              errno = EOVERFLOW;
++      }
++      return result;
++}
++
++#else /* !linux */
++
++#ifndef EOVERFLOW
++#ifdef EXT2_ET_INVALID_ARGUMENT
++#define EOVERFLOW EXT2_ET_INVALID_ARGUMENT
++#else
++#define EOVERFLOW 112
++#endif
++#endif
++
++blkid_loff_t blkid_llseek(int fd, blkid_loff_t offset, int origin)
++{
++#if defined(HAVE_LSEEK64) && defined(HAVE_LSEEK64_PROTOTYPE)
++      return lseek64 (fd, offset, origin);
++#else
++      if ((sizeof(off_t) < sizeof(blkid_loff_t)) &&
++          (offset >= ((blkid_loff_t) 1 << ((sizeof(off_t)*8) - 1)))) {
++              errno = EOVERFLOW;
++              return -1;
++      }
++      return lseek(fd, (off_t) offset, origin);
++#endif
++}
++
++#endif        /* linux */
++
++
+diff -Nur busybox-1.00/e2fsprogs/blkid/probe.c busybox/e2fsprogs/blkid/probe.c
+--- busybox-1.00/e2fsprogs/blkid/probe.c       1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/blkid/probe.c    2005-06-04 08:20:15.000000000 +0200
+@@ -0,0 +1,704 @@
++/*
++ * probe.c - identify a block device by its contents, and return a dev
++ *           struct with the details
++ *
++ * Copyright (C) 1999 by Andries Brouwer
++ * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
++ * Copyright (C) 2001 by Andreas Dilger
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the
++ * GNU Lesser General Public License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <string.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <fcntl.h>
++#include <sys/types.h>
++#ifdef HAVE_SYS_STAT_H
++#include <sys/stat.h>
++#endif
++#ifdef HAVE_SYS_MKDEV_H
++#include <sys/mkdev.h>
++#endif
++#ifdef HAVE_ERRNO_H
++#include <errno.h>
++#endif
++#include "blkidP.h"
++#include "uuid/uuid.h"
++#include "probe.h"
++
++/*
++ * This is a special case code to check for an MDRAID device.  We do
++ * this special since it requires checking for a superblock at the end
++ * of the device.
++ */
++static int check_mdraid(int fd, unsigned char *ret_uuid)
++{
++      struct mdp_superblock_s *md;
++      blkid_loff_t            offset;
++      char                    buf[4096];
++      
++      if (fd < 0)
++              return -BLKID_ERR_PARAM;
++
++      offset = (blkid_get_dev_size(fd) & ~((blkid_loff_t)65535)) - 65536;
++
++      if (blkid_llseek(fd, offset, 0) < 0 ||
++          read(fd, buf, 4096) != 4096)
++              return -BLKID_ERR_IO;
++
++      /* Check for magic number */
++      if (memcmp("\251+N\374", buf, 4))
++              return -BLKID_ERR_PARAM;
++
++      if (!ret_uuid)
++              return 0;
++      *ret_uuid = 0;
++
++      /* The MD UUID is not contiguous in the superblock, make it so */
++      md = (struct mdp_superblock_s *)buf;
++      if (md->set_uuid0 || md->set_uuid1 || md->set_uuid2 || md->set_uuid3) {
++              memcpy(ret_uuid, &md->set_uuid0, 4);
++              memcpy(ret_uuid, &md->set_uuid1, 12);
++      }
++      return 0;
++}
++
++static void set_uuid(blkid_dev dev, uuid_t uuid)
++{
++      char    str[37];
++
++      if (!uuid_is_null(uuid)) {
++              uuid_unparse(uuid, str);
++              blkid_set_tag(dev, "UUID", str, sizeof(str));
++      }
++}
++
++static void get_ext2_info(blkid_dev dev, unsigned char *buf)
++{
++      struct ext2_super_block *es = (struct ext2_super_block *) buf;
++      const char *label = 0;
++
++      DBG(DEBUG_PROBE, printf("ext2_sb.compat = %08X:%08X:%08X\n", 
++                 blkid_le32(es->s_feature_compat),
++                 blkid_le32(es->s_feature_incompat),
++                 blkid_le32(es->s_feature_ro_compat)));
++
++      if (strlen(es->s_volume_name))
++              label = es->s_volume_name;
++      blkid_set_tag(dev, "LABEL", label, sizeof(es->s_volume_name));
++
++      set_uuid(dev, es->s_uuid);
++}
++
++static int probe_ext3(int fd __BLKID_ATTR((unused)), 
++                    blkid_cache cache __BLKID_ATTR((unused)), 
++                    blkid_dev dev,
++                    struct blkid_magic *id, unsigned char *buf)
++{
++      struct ext2_super_block *es;
++
++      es = (struct ext2_super_block *)buf;
++
++      /* Distinguish between jbd and ext2/3 fs */
++      if (blkid_le32(es->s_feature_incompat) & 
++          EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
++              return -BLKID_ERR_PARAM;
++
++      /* Distinguish between ext3 and ext2 */
++      if (!(blkid_le32(es->s_feature_compat) &
++            EXT3_FEATURE_COMPAT_HAS_JOURNAL))
++              return -BLKID_ERR_PARAM;
++
++      get_ext2_info(dev, buf);
++
++      blkid_set_tag(dev, "SEC_TYPE", "ext2", sizeof("ext2"));
++
++      return 0;
++}
++
++static int probe_ext2(int fd __BLKID_ATTR((unused)), 
++                    blkid_cache cache __BLKID_ATTR((unused)), 
++                    blkid_dev dev,
++                    struct blkid_magic *id, unsigned char *buf)
++{
++      struct ext2_super_block *es;
++//    const char *sec_type = 0, *label = 0;
++
++      es = (struct ext2_super_block *)buf;
++
++      /* Distinguish between jbd and ext2/3 fs */
++      if (blkid_le32(es->s_feature_incompat) & 
++          EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
++              return -BLKID_ERR_PARAM;
++
++      get_ext2_info(dev, buf);
++
++      return 0;
++}
++
++static int probe_jbd(int fd __BLKID_ATTR((unused)), 
++                   blkid_cache cache __BLKID_ATTR((unused)), 
++                   blkid_dev dev, 
++                   struct blkid_magic *id __BLKID_ATTR((unused)), 
++                   unsigned char *buf)
++{
++      struct ext2_super_block *es = (struct ext2_super_block *) buf;
++
++      if (!(blkid_le32(es->s_feature_incompat) &
++            EXT3_FEATURE_INCOMPAT_JOURNAL_DEV))
++              return -BLKID_ERR_PARAM;
++
++      get_ext2_info(dev, buf);
++
++      return 0;
++}
++
++static int probe_vfat(int fd __BLKID_ATTR((unused)), 
++                    blkid_cache cache __BLKID_ATTR((unused)), 
++                    blkid_dev dev,
++                    struct blkid_magic *id __BLKID_ATTR((unused)), 
++                    unsigned char *buf)
++{
++      struct vfat_super_block *vs;
++      char serno[10];
++      const char *label = 0;
++      int label_len = 0;
++
++      vs = (struct vfat_super_block *)buf;
++
++      if (strncmp(vs->vs_label, "NO NAME", 7)) {
++              char *end = vs->vs_label + sizeof(vs->vs_label) - 1;
++
++              while (*end == ' ' && end >= vs->vs_label)
++                      --end;
++              if (end >= vs->vs_label) {
++                      label = vs->vs_label;
++                      label_len = end - vs->vs_label + 1;
++              }
++      }
++
++      /* We can't just print them as %04X, because they are unaligned */
++      sprintf(serno, "%02X%02X-%02X%02X", vs->vs_serno[3], vs->vs_serno[2],
++              vs->vs_serno[1], vs->vs_serno[0]);
++      blkid_set_tag(dev, "LABEL", label, label_len);
++      blkid_set_tag(dev, "UUID", serno, sizeof(serno));
++
++      return 0;
++}
++
++static int probe_msdos(int fd __BLKID_ATTR((unused)), 
++                     blkid_cache cache __BLKID_ATTR((unused)), 
++                     blkid_dev dev,
++                     struct blkid_magic *id __BLKID_ATTR((unused)), 
++                     unsigned char *buf)
++{
++      struct msdos_super_block *ms = (struct msdos_super_block *) buf;
++      char serno[10];
++      const char *label = 0;
++      int label_len = 0;
++
++      if (strncmp(ms->ms_label, "NO NAME", 7)) {
++              char *end = ms->ms_label + sizeof(ms->ms_label) - 1;
++
++              while (*end == ' ' && end >= ms->ms_label)
++                      --end;
++              if (end >= ms->ms_label) {
++                      label = ms->ms_label;
++                      label_len = end - ms->ms_label + 1;
++              }
++      }
++
++      /* We can't just print them as %04X, because they are unaligned */
++      sprintf(serno, "%02X%02X-%02X%02X", ms->ms_serno[3], ms->ms_serno[2],
++              ms->ms_serno[1], ms->ms_serno[0]);
++      blkid_set_tag(dev, "UUID", serno, 0);
++      blkid_set_tag(dev, "LABEL", label, label_len);
++      blkid_set_tag(dev, "SEC_TYPE", "msdos", sizeof("msdos"));
++
++      return 0;
++}
++
++static int probe_xfs(int fd __BLKID_ATTR((unused)), 
++                   blkid_cache cache __BLKID_ATTR((unused)), 
++                   blkid_dev dev,
++                   struct blkid_magic *id __BLKID_ATTR((unused)), 
++                   unsigned char *buf)
++{
++      struct xfs_super_block *xs;
++      const char *label = 0;
++
++      xs = (struct xfs_super_block *)buf;
++
++      if (strlen(xs->xs_fname))
++              label = xs->xs_fname;
++      blkid_set_tag(dev, "LABEL", label, sizeof(xs->xs_fname));
++      set_uuid(dev, xs->xs_uuid);
++      return 0;
++}
++
++static int probe_reiserfs(int fd __BLKID_ATTR((unused)), 
++                        blkid_cache cache __BLKID_ATTR((unused)), 
++                        blkid_dev dev,
++                        struct blkid_magic *id, unsigned char *buf)
++{
++      struct reiserfs_super_block *rs = (struct reiserfs_super_block *) buf;
++      unsigned int blocksize;
++      const char *label = 0;
++
++      blocksize = blkid_le16(rs->rs_blocksize);
++
++      /* If the superblock is inside the journal, we have the wrong one */
++      if (id->bim_kboff/(blocksize>>10) > blkid_le32(rs->rs_journal_block))
++              return -BLKID_ERR_BIG;
++
++      /* LABEL/UUID are only valid for later versions of Reiserfs v3.6. */
++      if (!strcmp(id->bim_magic, "ReIsEr2Fs") ||
++          !strcmp(id->bim_magic, "ReIsEr3Fs")) {
++              if (strlen(rs->rs_label))
++                      label = rs->rs_label;
++              set_uuid(dev, rs->rs_uuid);
++      }
++      blkid_set_tag(dev, "LABEL", label, sizeof(rs->rs_label));
++
++      return 0;
++}
++
++static int probe_jfs(int fd __BLKID_ATTR((unused)), 
++                   blkid_cache cache __BLKID_ATTR((unused)), 
++                   blkid_dev dev,
++                   struct blkid_magic *id __BLKID_ATTR((unused)), 
++                   unsigned char *buf)
++{
++      struct jfs_super_block *js;
++      const char *label = 0;
++
++      js = (struct jfs_super_block *)buf;
++
++      if (strlen((char *) js->js_label))
++              label = (char *) js->js_label;
++      blkid_set_tag(dev, "LABEL", label, sizeof(js->js_label));
++      set_uuid(dev, js->js_uuid);
++      return 0;
++}
++
++static int probe_romfs(int fd __BLKID_ATTR((unused)), 
++                     blkid_cache cache __BLKID_ATTR((unused)), 
++                     blkid_dev dev,
++                     struct blkid_magic *id __BLKID_ATTR((unused)), 
++                     unsigned char *buf)
++{
++      struct romfs_super_block *ros;
++      const char *label = 0;
++
++      ros = (struct romfs_super_block *)buf;
++
++      if (strlen((char *) ros->ros_volume))
++              label = (char *) ros->ros_volume;
++      blkid_set_tag(dev, "LABEL", label, 0);
++      return 0;
++}
++
++static int probe_swap0(int fd __BLKID_ATTR((unused)),
++                     blkid_cache cache __BLKID_ATTR((unused)),
++                     blkid_dev dev,
++                     struct blkid_magic *id __BLKID_ATTR((unused)),
++                     unsigned char *buf __BLKID_ATTR((unused)))
++{
++      blkid_set_tag(dev, "UUID", 0, 0);
++      blkid_set_tag(dev, "LABEL", 0, 0);
++      return 0;
++}
++
++static int probe_swap1(int fd,
++                     blkid_cache cache __BLKID_ATTR((unused)),
++                     blkid_dev dev,
++                     struct blkid_magic *id __BLKID_ATTR((unused)),
++                     unsigned char *buf __BLKID_ATTR((unused)))
++{
++      struct swap_id_block *sws;
++//    const char *label = 0;
++
++      probe_swap0(fd, cache, dev, id, buf);
++      /*
++       * Version 1 swap headers are always located at offset of 1024
++       * bytes, although the swap signature itself is located at the
++       * end of the page (which may vary depending on hardware
++       * pagesize).
++       */
++      if (lseek(fd, 1024, SEEK_SET) < 0) return 1;
++      if (!(sws = (struct swap_id_block *)malloc(1024))) return 1;
++      if (read(fd, sws, 1024) != 1024) {
++              free(sws);
++              return 1;
++      }
++
++      /* arbitrary sanity check.. is there any garbage down there? */
++      if (sws->sws_pad[32] == 0 && sws->sws_pad[33] == 0)  {
++              if (sws->sws_volume[0])
++                      blkid_set_tag(dev, "LABEL", sws->sws_volume, 
++                                    sizeof(sws->sws_volume));
++              if (sws->sws_uuid[0])
++                      set_uuid(dev, sws->sws_uuid);
++      }
++      free(sws);
++
++      return 0;
++}
++
++static const char
++*udf_magic[] = { "BEA01", "BOOT2", "CD001", "CDW02", "NSR02",
++               "NSR03", "TEA01", 0 };
++
++static int probe_udf(int fd, blkid_cache cache __BLKID_ATTR((unused)), 
++                   blkid_dev dev __BLKID_ATTR((unused)),
++                     struct blkid_magic *id __BLKID_ATTR((unused)), 
++                   unsigned char *buf __BLKID_ATTR((unused)))
++{
++      int j, bs;
++      struct iso_volume_descriptor isosb;
++      const char ** m;
++
++      /* determine the block size by scanning in 2K increments
++         (block sizes larger than 2K will be null padded) */
++      for (bs = 1; bs < 16; bs++) {
++              lseek(fd, bs*2048+32768, SEEK_SET);
++              if (read(fd, (char *)&isosb, sizeof(isosb)) != sizeof(isosb))
++                      return 1;
++              if (isosb.id[0])
++                      break;
++      }
++
++      /* Scan up to another 64 blocks looking for additional VSD's */
++      for (j = 1; j < 64; j++) {
++              if (j > 1) {
++                      lseek(fd, j*bs*2048+32768, SEEK_SET);
++                      if (read(fd, (char *)&isosb, sizeof(isosb))
++                          != sizeof(isosb))
++                              return 1;
++              }
++              /* If we find NSR0x then call it udf:
++                 NSR01 for UDF 1.00
++                 NSR02 for UDF 1.50
++                 NSR03 for UDF 2.00 */
++              if (!strncmp(isosb.id, "NSR0", 4))
++                      return 0;
++              for (m = udf_magic; *m; m++)
++                      if (!strncmp(*m, isosb.id, 5))
++                              break;
++              if (*m == 0)
++                      return 1;
++      }
++      return 1;
++}
++
++static int probe_ocfs(int fd __BLKID_ATTR((unused)), 
++                    blkid_cache cache __BLKID_ATTR((unused)), 
++                    blkid_dev dev,
++                    struct blkid_magic *id __BLKID_ATTR((unused)), 
++                    unsigned char *buf)
++{
++      struct ocfs_volume_header ovh;
++      struct ocfs_volume_label ovl;
++      __u32 major;
++
++      memcpy(&ovh, buf, sizeof(ovh));
++      memcpy(&ovl, buf+512, sizeof(ovl));
++
++      major = ocfsmajor(ovh);
++      if (major == 1)
++              blkid_set_tag(dev,"SEC_TYPE","ocfs1",sizeof("ocfs1"));
++      else if (major >= 9)
++              blkid_set_tag(dev,"SEC_TYPE","ntocfs",sizeof("ntocfs"));
++      
++      blkid_set_tag(dev, "LABEL", ovl.label, ocfslabellen(ovl));
++      blkid_set_tag(dev, "MOUNT", ovh.mount, ocfsmountlen(ovh));
++      set_uuid(dev, ovl.vol_id);
++      return 0;
++}
++
++static int probe_ocfs2(int fd __BLKID_ATTR((unused)), 
++                     blkid_cache cache __BLKID_ATTR((unused)), 
++                     blkid_dev dev,
++                     struct blkid_magic *id __BLKID_ATTR((unused)), 
++                     unsigned char *buf)
++{
++      struct ocfs2_super_block *osb;
++
++      osb = (struct ocfs2_super_block *)buf;
++
++      blkid_set_tag(dev, "LABEL", osb->s_label, sizeof(osb->s_label));
++      set_uuid(dev, osb->s_uuid);
++      return 0;
++}
++
++static int probe_oracleasm(int fd __BLKID_ATTR((unused)), 
++                         blkid_cache cache __BLKID_ATTR((unused)), 
++                         blkid_dev dev,
++                         struct blkid_magic *id __BLKID_ATTR((unused)), 
++                         unsigned char *buf)
++{
++      struct oracle_asm_disk_label *dl;
++
++      dl = (struct oracle_asm_disk_label *)buf;
++
++      blkid_set_tag(dev, "LABEL", dl->dl_id, sizeof(dl->dl_id));
++      return 0;
++}
++
++/*
++ * BLKID_BLK_OFFS is at least as large as the highest bim_kboff defined
++ * in the type_array table below + bim_kbalign.
++ *
++ * When probing for a lot of magics, we handle everything in 1kB buffers so
++ * that we don't have to worry about reading each combination of block sizes.
++ */
++#define BLKID_BLK_OFFS        64      /* currently reiserfs */
++
++/*
++ * Various filesystem magics that we can check for.  Note that kboff and
++ * sboff are in kilobytes and bytes respectively.  All magics are in
++ * byte strings so we don't worry about endian issues.
++ */
++static struct blkid_magic type_array[] = {
++/*  type     kboff   sboff len  magic                 probe */
++  { "oracleasm", 0,   32,  8, "ORCLDISK",             probe_oracleasm },
++  { "ntfs",      0,      3,  8, "NTFS    ",             0 },
++  { "jbd",     1,   0x38,  2, "\123\357",             probe_jbd },
++  { "ext3",    1,   0x38,  2, "\123\357",             probe_ext3 },
++  { "ext2",    1,   0x38,  2, "\123\357",             probe_ext2 },
++  { "reiserfs",        8,   0x34,  8, "ReIsErFs",             probe_reiserfs },
++  { "reiserfs", 64,   0x34,  9, "ReIsEr2Fs",          probe_reiserfs },
++  { "reiserfs", 64,   0x34,  9, "ReIsEr3Fs",          probe_reiserfs },
++  { "reiserfs", 64,   0x34,  8, "ReIsErFs",           probe_reiserfs },
++  { "reiserfs",        8,     20,  8, "ReIsErFs",             probe_reiserfs },
++  { "vfat",      0,   0x52,  5, "MSWIN",                probe_vfat },
++  { "vfat",      0,   0x52,  8, "FAT32   ",             probe_vfat },
++  { "vfat",      0,   0x36,  5, "MSDOS",                probe_msdos },
++  { "vfat",      0,   0x36,  8, "FAT16   ",             probe_msdos },
++  { "vfat",      0,   0x36,  8, "FAT12   ",             probe_msdos },
++  { "minix",     1,   0x10,  2, "\177\023",             0 },
++  { "minix",     1,   0x10,  2, "\217\023",             0 },
++  { "minix",   1,   0x10,  2, "\150\044",             0 },
++  { "minix",   1,   0x10,  2, "\170\044",             0 },
++  { "vxfs",    1,      0,  4, "\365\374\001\245",     0 },
++  { "xfs",     0,      0,  4, "XFSB",                 probe_xfs },
++  { "romfs",   0,      0,  8, "-rom1fs-",             probe_romfs },
++  { "bfs",     0,      0,  4, "\316\372\173\033",     0 },
++  { "cramfs",  0,      0,  4, "E=\315\034",           0 },
++  { "qnx4",    0,      4,  6, "QNX4FS",               0 },
++  { "udf",    32,      1,  5, "BEA01",                probe_udf },
++  { "udf",    32,      1,  5, "BOOT2",                probe_udf },
++  { "udf",    32,      1,  5, "CD001",                probe_udf },
++  { "udf",    32,      1,  5, "CDW02",                probe_udf },
++  { "udf",    32,      1,  5, "NSR02",                probe_udf },
++  { "udf",    32,      1,  5, "NSR03",                probe_udf },
++  { "udf",    32,      1,  5, "TEA01",                probe_udf },
++  { "iso9660",        32,      1,  5, "CD001",                0 },
++  { "iso9660",        32,      9,  5, "CDROM",                0 },
++  { "jfs",    32,      0,  4, "JFS1",                 probe_jfs },
++  { "hfs",     1,      0,  2, "BD",                   0 },
++  { "ufs",     8,  0x55c,  4, "T\031\001\000",        0 },
++  { "hpfs",    8,      0,  4, "I\350\225\371",        0 },
++  { "sysv",    0,  0x3f8,  4, "\020~\030\375",        0 },
++  { "swap",    0,  0xff6, 10, "SWAP-SPACE",           probe_swap0 },
++  { "swap",    0,  0xff6, 10, "SWAPSPACE2",           probe_swap1 },
++  { "swap",    0, 0x1ff6, 10, "SWAP-SPACE",           probe_swap0 },
++  { "swap",    0, 0x1ff6, 10, "SWAPSPACE2",           probe_swap1 },
++  { "swap",    0, 0x3ff6, 10, "SWAP-SPACE",           probe_swap0 },
++  { "swap",    0, 0x3ff6, 10, "SWAPSPACE2",           probe_swap1 },
++  { "swap",    0, 0x7ff6, 10, "SWAP-SPACE",           probe_swap0 },
++  { "swap",    0, 0x7ff6, 10, "SWAPSPACE2",           probe_swap1 },
++  { "swap",    0, 0xfff6, 10, "SWAP-SPACE",           probe_swap0 },
++  { "swap",    0, 0xfff6, 10, "SWAPSPACE2",           probe_swap1 },
++  { "ocfs",    0,      8,  9, "OracleCFS",            probe_ocfs },
++  { "ocfs2",   1,      0,  6, "OCFSV2",               probe_ocfs2 },
++  { "ocfs2",   2,      0,  6, "OCFSV2",               probe_ocfs2 },
++  { "ocfs2",   4,      0,  6, "OCFSV2",               probe_ocfs2 },
++  { "ocfs2",   8,      0,  6, "OCFSV2",               probe_ocfs2 },
++  {   NULL,    0,      0,  0, NULL,                   NULL }
++};
++
++/*
++ * Verify that the data in dev is consistent with what is on the actual
++ * block device (using the devname field only).  Normally this will be
++ * called when finding items in the cache, but for long running processes
++ * is also desirable to revalidate an item before use.
++ *
++ * If we are unable to revalidate the data, we return the old data and
++ * do not set the BLKID_BID_FL_VERIFIED flag on it.
++ */
++blkid_dev blkid_verify(blkid_cache cache, blkid_dev dev)
++{
++      struct blkid_magic *id;
++      unsigned char *bufs[BLKID_BLK_OFFS + 1], *buf;
++      const char *type;
++      struct stat st;
++      time_t diff, now;
++      int fd, idx;
++
++      if (!dev)
++              return NULL;
++
++      now = time(0);
++      diff = now - dev->bid_time;
++
++      if ((now < dev->bid_time) ||
++          (diff < BLKID_PROBE_MIN) || 
++          (dev->bid_flags & BLKID_BID_FL_VERIFIED &&
++           diff < BLKID_PROBE_INTERVAL))
++              return dev;
++
++      DBG(DEBUG_PROBE,
++          printf("need to revalidate %s (time since last check %lu)\n", 
++                 dev->bid_name, diff));
++
++      if (((fd = open(dev->bid_name, O_RDONLY)) < 0) ||
++          (fstat(fd, &st) < 0)) {
++              if (errno == ENXIO || errno == ENODEV || errno == ENOENT) {
++                      blkid_free_dev(dev);
++                      return NULL;
++              }
++              /* We don't have read permission, just return cache data. */
++              DBG(DEBUG_PROBE,
++                  printf("returning unverified data for %s\n",
++                         dev->bid_name));
++              return dev;
++      }
++
++      memset(bufs, 0, sizeof(bufs));
++      
++      /*
++       * Iterate over the type array.  If we already know the type,
++       * then try that first.  If it doesn't work, then blow away
++       * the type information, and try again.
++       * 
++       */
++try_again:
++      type = 0;
++      if (!dev->bid_type || !strcmp(dev->bid_type, "mdraid")) {
++              uuid_t  uuid;
++
++              if (check_mdraid(fd, uuid) == 0) {
++                      set_uuid(dev, uuid);
++                      type = "mdraid";
++                      goto found_type;
++              }
++      }
++      for (id = type_array; id->bim_type; id++) {
++              if (dev->bid_type &&
++                  strcmp(id->bim_type, dev->bid_type))
++                      continue;
++
++              idx = id->bim_kboff + (id->bim_sboff >> 10);
++              if (idx > BLKID_BLK_OFFS || idx < 0)
++                      continue;
++              buf = bufs[idx];
++              if (!buf) {
++                      if (lseek(fd, idx << 10, SEEK_SET) < 0)
++                              continue;
++
++                      if (!(buf = (unsigned char *)malloc(1024)))
++                              continue;
++                      
++                      if (read(fd, buf, 1024) != 1024) {
++                              free(buf);
++                              continue;
++                      }
++                      bufs[idx] = buf;
++              }
++
++              if (memcmp(id->bim_magic, buf + (id->bim_sboff&0x3ff),
++                         id->bim_len))
++                      continue;
++
++              if ((id->bim_probe == NULL) ||
++                  (id->bim_probe(fd, cache, dev, id, buf) == 0)) {
++                      type = id->bim_type;
++                      goto found_type;
++              }
++      }
++
++      if (!id->bim_type && dev->bid_type) {
++              /*
++               * Zap the device filesystem type and try again
++               */
++              blkid_set_tag(dev, "TYPE", 0, 0);
++              blkid_set_tag(dev, "SEC_TYPE", 0, 0);
++              blkid_set_tag(dev, "LABEL", 0, 0);
++              blkid_set_tag(dev, "UUID", 0, 0);
++              goto try_again;
++      }
++
++      if (!dev->bid_type) {
++              blkid_free_dev(dev);
++              return NULL;
++      }
++              
++found_type:
++      if (dev && type) {
++              dev->bid_devno = st.st_rdev;
++              dev->bid_time = time(0);
++              dev->bid_flags |= BLKID_BID_FL_VERIFIED;
++              cache->bic_flags |= BLKID_BIC_FL_CHANGED;
++
++              blkid_set_tag(dev, "TYPE", type, 0);
++                              
++              DBG(DEBUG_PROBE, printf("%s: devno 0x%04Lx, type %s\n",
++                         dev->bid_name, st.st_rdev, type));
++      }
++
++      close(fd);
++
++      return dev;
++}
++
++int blkid_known_fstype(const char *fstype)
++{
++      struct blkid_magic *id;
++
++      for (id = type_array; id->bim_type; id++) {
++              if (strcmp(fstype, id->bim_type) == 0)
++                      return 1;
++      }
++      return 0;
++}
++
++#ifdef TEST_PROGRAM
++int main(int argc, char **argv)
++{
++      blkid_dev dev;
++      blkid_cache cache;
++      int ret;
++
++      blkid_debug_mask = DEBUG_ALL;
++      if (argc != 2) {
++              fprintf(stderr, "Usage: %s device\n"
++                      "Probe a single device to determine type\n", argv[0]);
++              exit(1);
++      }
++      if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) {
++              fprintf(stderr, "%s: error creating cache (%d)\n",
++                      argv[0], ret);
++              exit(1);
++      }
++      dev = blkid_get_dev(cache, argv[1], BLKID_DEV_NORMAL);
++      if (!dev) {
++              printf("%s: %s has an unsupported type\n", argv[0], argv[1]);
++              return (1);
++      }
++      printf("%s is type %s\n", argv[1], dev->bid_type ?
++              dev->bid_type : "(null)");
++      if (dev->bid_label)
++              printf("\tlabel is '%s'\n", dev->bid_label);
++      if (dev->bid_uuid)
++              printf("\tuuid is %s\n", dev->bid_uuid);
++      
++      blkid_free_dev(dev);
++      return (0);
++}
++#endif
+diff -Nur busybox-1.00/e2fsprogs/blkid/probe.h busybox/e2fsprogs/blkid/probe.h
+--- busybox-1.00/e2fsprogs/blkid/probe.h       1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/blkid/probe.h    2005-06-04 08:20:15.000000000 +0200
+@@ -0,0 +1,359 @@
++/*
++ * probe.h - constants and on-disk structures for extracting device data
++ *
++ * Copyright (C) 1999 by Andries Brouwer
++ * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
++ * Copyright (C) 2001 by Andreas Dilger
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the
++ * GNU Lesser General Public License.
++ * %End-Header%
++ */
++
++#ifndef _BLKID_PROBE_H
++#define _BLKID_PROBE_H
++
++#include <linux/types.h>
++
++struct blkid_magic;
++
++typedef int (*blkid_probe_t)(int fd, blkid_cache cache, blkid_dev dev, 
++                           struct blkid_magic *id, unsigned char *buf);
++
++struct blkid_magic {
++      const char      *bim_type;      /* type name for this magic */
++      long            bim_kboff;      /* kilobyte offset of superblock */
++      unsigned        bim_sboff;      /* byte offset within superblock */
++      unsigned        bim_len;        /* length of magic */
++      const char      *bim_magic;     /* magic string */
++      blkid_probe_t   bim_probe;      /* probe function */
++};
++
++/*
++ * Structures for each of the content types we want to extract information
++ * from.  We do not necessarily need the magic field here, because we have
++ * already identified the content type before we get this far.  It may still
++ * be useful if there are probe functions which handle multiple content types.
++ */
++struct ext2_super_block {
++      __u32           s_inodes_count;
++      __u32           s_blocks_count;
++      __u32           s_r_blocks_count;
++      __u32           s_free_blocks_count;
++      __u32           s_free_inodes_count;
++      __u32           s_first_data_block;
++      __u32           s_log_block_size;
++      __u32           s_dummy3[7];
++      unsigned char   s_magic[2];
++      __u16           s_state;
++      __u32           s_dummy5[8];
++      __u32           s_feature_compat;
++      __u32           s_feature_incompat;
++      __u32           s_feature_ro_compat;
++      unsigned char   s_uuid[16];
++      char       s_volume_name[16];
++};
++#define EXT3_FEATURE_COMPAT_HAS_JOURNAL               0x00000004
++#define EXT3_FEATURE_INCOMPAT_RECOVER         0x00000004
++#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV     0x00000008
++
++struct xfs_super_block {
++      unsigned char   xs_magic[4];
++      __u32           xs_blocksize;
++      __u64           xs_dblocks;
++      __u64           xs_rblocks;
++      __u32           xs_dummy1[2];
++      unsigned char   xs_uuid[16];
++      __u32           xs_dummy2[15];
++      char            xs_fname[12];
++      __u32           xs_dummy3[2];
++      __u64           xs_icount;
++      __u64           xs_ifree;
++      __u64           xs_fdblocks;
++};
++
++struct reiserfs_super_block {
++      __u32           rs_blocks_count;
++      __u32           rs_free_blocks;
++      __u32           rs_root_block;
++      __u32           rs_journal_block;
++      __u32           rs_journal_dev;
++      __u32           rs_orig_journal_size;
++      __u32           rs_dummy2[5];
++      __u16           rs_blocksize;
++      __u16           rs_dummy3[3];
++      unsigned char   rs_magic[12];
++      __u32           rs_dummy4[5];
++      unsigned char   rs_uuid[16];
++      char            rs_label[16];
++};
++
++struct jfs_super_block {
++      unsigned char   js_magic[4];
++      __u32           js_version;
++      __u64           js_size;
++      __u32           js_bsize;
++      __u32           js_dummy1;
++      __u32           js_pbsize;
++      __u32           js_dummy2[27];
++      unsigned char   js_uuid[16];
++      unsigned char   js_label[16];
++      unsigned char   js_loguuid[16];
++};
++
++struct romfs_super_block {
++      unsigned char   ros_magic[8];
++      __u32           ros_dummy1[2];
++      unsigned char   ros_volume[16];
++};
++
++struct swap_id_block {
++/*    unsigned char   sws_boot[1024]; */
++      __u32           sws_version;
++      __u32           sws_lastpage;
++      __u32           sws_nrbad;
++      unsigned char   sws_uuid[16];
++      unsigned char   sws_volume[16];
++      unsigned char   sws_pad[117];
++      __u32           sws_badpg;
++};
++
++/* Yucky misaligned values */
++struct vfat_super_block {
++/* 00*/       unsigned char   vs_ignored[3];
++/* 03*/       unsigned char   vs_sysid[8];
++/* 0b*/       unsigned char   vs_sector_size[2];
++/* 0d*/       __u8            vs_cluster_size;
++/* 0e*/       __u16           vs_reserved;
++/* 10*/       __u8            vs_fats;
++/* 11*/       unsigned char   vs_dir_entries[2];
++/* 13*/       unsigned char   vs_sectors[2];
++/* 15*/       unsigned char   vs_media;
++/* 16*/       __u16           vs_fat_length;
++/* 18*/       __u16           vs_secs_track;
++/* 1a*/       __u16           vs_heads;
++/* 1c*/       __u32           vs_hidden;
++/* 20*/       __u32           vs_total_sect;
++/* 24*/       __u32           vs_fat32_length;
++/* 28*/       __u16           vs_flags;
++/* 2a*/       __u8            vs_version[2];
++/* 2c*/       __u32           vs_root_cluster;
++/* 30*/       __u16           vs_insfo_sector;
++/* 32*/       __u16           vs_backup_boot;
++/* 34*/       __u16           vs_reserved2[6];
++/* 40*/       unsigned char   vs_unknown[3];
++/* 43*/       unsigned char   vs_serno[4];
++/* 47*/       char            vs_label[11];
++/* 52*/       unsigned char   vs_magic[8];
++/* 5a*/       unsigned char   vs_dummy2[164];
++/*1fe*/       unsigned char   vs_pmagic[2];
++};
++
++/* Yucky misaligned values */
++struct msdos_super_block {
++/* 00*/       unsigned char   ms_ignored[3];
++/* 03*/       unsigned char   ms_sysid[8];
++/* 0b*/       unsigned char   ms_sector_size[2];
++/* 0d*/       __u8            ms_cluster_size;
++/* 0e*/       __u16           ms_reserved;
++/* 10*/       __u8            ms_fats;
++/* 11*/       unsigned char   ms_dir_entries[2];
++/* 13*/       unsigned char   ms_sectors[2];
++/* 15*/       unsigned char   ms_media;
++/* 16*/       __u16           ms_fat_length;
++/* 18*/       __u16           ms_secs_track;
++/* 1a*/       __u16           ms_heads;
++/* 1c*/       __u32           ms_hidden;
++/* 20*/       __u32           ms_total_sect;
++/* 24*/       unsigned char   ms_unknown[3];
++/* 27*/       unsigned char   ms_serno[4];
++/* 2b*/       char            ms_label[11];
++/* 36*/       unsigned char   ms_magic[8];
++/* 3d*/       unsigned char   ms_dummy2[192];
++/*1fe*/       unsigned char   ms_pmagic[2];
++};
++
++struct minix_super_block {
++      __u16           ms_ninodes;
++      __u16           ms_nzones;
++      __u16           ms_imap_blocks;
++      __u16           ms_zmap_blocks;
++      __u16           ms_firstdatazone;
++      __u16           ms_log_zone_size;
++      __u32           ms_max_size;
++      unsigned char   ms_magic[2];
++      __u16           ms_state;
++      __u32           ms_zones;
++};
++
++struct mdp_superblock_s {
++      __u32 md_magic;
++      __u32 major_version;
++      __u32 minor_version;
++      __u32 patch_version;
++      __u32 gvalid_words;
++      __u32 set_uuid0;
++      __u32 ctime;
++      __u32 level;
++      __u32 size;
++      __u32 nr_disks;
++      __u32 raid_disks;
++      __u32 md_minor;
++      __u32 not_persistent;
++      __u32 set_uuid1;
++      __u32 set_uuid2;
++      __u32 set_uuid3;
++};
++
++struct hfs_super_block {
++      char    h_magic[2];
++      char    h_dummy[18];
++      __u32   h_blksize;
++};
++
++struct ocfs_volume_header {
++      unsigned char   minor_version[4];
++      unsigned char   major_version[4];
++      unsigned char   signature[128];
++      unsigned char  mount[128];
++      unsigned char  mount_len[2];
++};
++
++struct ocfs_volume_label {
++      unsigned char   disk_lock[48];
++      unsigned char   label[64];      
++      unsigned char   label_len[2];
++      unsigned char  vol_id[16];
++      unsigned char  vol_id_len[2];
++};
++
++#define ocfsmajor(o) ((__u32)o.major_version[0] \
++                   + (((__u32) o.major_version[1]) << 8) \
++                   + (((__u32) o.major_version[2]) << 16) \
++                   + (((__u32) o.major_version[3]) << 24))
++#define ocfslabellen(o)       ((__u32)o.label_len[0] + (((__u32) o.label_len[1]) << 8))
++#define ocfsmountlen(o)       ((__u32)o.mount_len[0] + (((__u32) o.mount_len[1])<<8))
++
++#define OCFS_MAGIC "OracleCFS"
++
++struct ocfs2_super_block {
++      unsigned char  signature[8];
++      unsigned char  s_dummy1[184];
++      unsigned char  s_dummy2[80];
++      unsigned char  s_label[64];
++      unsigned char  s_uuid[16];
++};
++
++#define OCFS2_MIN_BLOCKSIZE             512
++#define OCFS2_MAX_BLOCKSIZE             4096
++
++#define OCFS2_SUPER_BLOCK_BLKNO         2
++
++#define OCFS2_SUPER_BLOCK_SIGNATURE     "OCFSV2"
++
++struct oracle_asm_disk_label {
++      char dummy[32];
++      char dl_tag[8];
++      char dl_id[24];
++};
++
++#define ORACLE_ASM_DISK_LABEL_MARKED    "ORCLDISK"
++#define ORACLE_ASM_DISK_LABEL_OFFSET    32
++
++#define ISODCL(from, to) (to - from + 1)
++struct iso_volume_descriptor {
++      char type[ISODCL(1,1)]; /* 711 */
++      char id[ISODCL(2,6)];
++      char version[ISODCL(7,7)];
++      char data[ISODCL(8,2048)];
++};
++
++/*
++ * Byte swap functions
++ */
++#ifdef __GNUC__
++#define _INLINE_ static __inline__
++#else                         /* For Watcom C */
++#define _INLINE_ static inline
++#endif
++
++static __u16 blkid_swab16(__u16 val);
++static __u32 blkid_swab32(__u32 val);
++static __u64 blkid_swab64(__u64 val);
++
++#if ((defined __GNUC__) && \
++     (defined(__i386__) || defined(__i486__) || defined(__i586__)))
++
++#define _BLKID_HAVE_ASM_BITOPS_
++
++_INLINE_ __u32 blkid_swab32(__u32 val)
++{
++#ifdef EXT2FS_REQUIRE_486
++      __asm__("bswap %0" : "=r" (val) : "0" (val));
++#else
++      __asm__("xchgb %b0,%h0\n\t"     /* swap lower bytes     */
++              "rorl $16,%0\n\t"       /* swap words           */
++              "xchgb %b0,%h0"         /* swap higher bytes    */
++              :"=q" (val)
++              : "0" (val));
++#endif
++      return val;
++}
++
++_INLINE_ __u16 blkid_swab16(__u16 val)
++{
++      __asm__("xchgb %b0,%h0"         /* swap bytes           */ \
++              : "=q" (val) \
++              :  "0" (val)); \
++              return val;
++}
++
++_INLINE_ __u64 blkid_swab64(__u64 val)
++{
++      return (blkid_swab32(val >> 32) |
++              (((__u64) blkid_swab32(val & 0xFFFFFFFFUL)) << 32));
++}
++#endif
++
++#if !defined(_BLKID_HAVE_ASM_BITOPS_)
++
++_INLINE_  __u16 blkid_swab16(__u16 val)
++{
++      return (val >> 8) | (val << 8);
++}
++
++_INLINE_ __u32 blkid_swab32(__u32 val)
++{
++      return ((val>>24) | ((val>>8)&0xFF00) |
++              ((val<<8)&0xFF0000) | (val<<24));
++}
++
++_INLINE_ __u64 blkid_swab64(__u64 val)
++{
++      return (blkid_swab32(val >> 32) |
++              (((__u64) blkid_swab32(val & 0xFFFFFFFFUL)) << 32));
++}
++#endif 
++
++
++
++#if  __BYTE_ORDER == __BIG_ENDIAN
++#define blkid_le16(x) blkid_swab16(x)
++#define blkid_le32(x) blkid_swab32(x)
++#define blkid_le64(x) blkid_swab64(x)
++#define blkid_be16(x) (x)
++#define blkid_be32(x) (x)
++#define blkid_be64(x) (x)
++#else
++#define blkid_le16(x) (x)
++#define blkid_le32(x) (x)
++#define blkid_le64(x) (x)
++#define blkid_be16(x) blkid_swab16(x)
++#define blkid_be32(x) blkid_swab32(x)
++#define blkid_be64(x) blkid_swab64(x)
++#endif
++
++#undef _INLINE_
++
++#endif /* _BLKID_PROBE_H */
+diff -Nur busybox-1.00/e2fsprogs/blkid/read.c busybox/e2fsprogs/blkid/read.c
+--- busybox-1.00/e2fsprogs/blkid/read.c        1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/blkid/read.c     2005-06-04 08:20:15.000000000 +0200
+@@ -0,0 +1,459 @@
++/*
++ * read.c - read the blkid cache from disk, to avoid scanning all devices
++ *
++ * Copyright (C) 2001, 2003 Theodore Y. Ts'o
++ * Copyright (C) 2001 Andreas Dilger
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the
++ * GNU Lesser General Public License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <ctype.h>
++#include <string.h>
++#include <time.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <fcntl.h>
++#include <unistd.h>
++#if HAVE_ERRNO_H
++#include <errno.h>
++#endif
++
++#include "blkidP.h"
++#include "uuid/uuid.h"
++
++#ifdef HAVE_STRTOULL
++#define __USE_ISOC9X
++#define STRTOULL strtoull /* defined in stdlib.h if you try hard enough */
++#else
++/* FIXME: need to support real strtoull here */
++#define STRTOULL strtoul
++#endif
++
++#if HAVE_STDLIB_H
++#include <stdlib.h>
++#endif
++
++/*
++ * File format:
++ *
++ *    <device [<NAME="value"> ...]>device_name</device>
++ *
++ *    The following tags are required for each entry:
++ *    <ID="id">       unique (within this file) ID number of this device
++ *    <TIME="time">   (ascii time_t) time this entry was last read from disk
++ *    <TYPE="type">   (detected) type of filesystem/data for this partition
++ *
++ *    The following tags may be present, depending on the device contents
++ *    <LABEL="label"> (user supplied) label (volume name, etc)
++ *    <UUID="uuid">   (generated) universally unique identifier (serial no)
++ */
++
++static char *skip_over_blank(char *cp)
++{
++      while (*cp && isspace(*cp))
++              cp++;
++      return cp;
++}
++
++static char *skip_over_word(char *cp)
++{
++      char ch;
++
++      while ((ch = *cp)) {
++              /* If we see a backslash, skip the next character */
++              if (ch == '\\') {
++                      cp++;
++                      if (*cp == '\0')
++                              break;
++                      cp++;
++                      continue;
++              }
++              if (isspace(ch) || ch == '<' || ch == '>')
++                      break;
++              cp++;
++      }
++      return cp;
++}
++
++static char *strip_line(char *line)
++{
++      char    *p;
++
++      line = skip_over_blank(line);
++
++      p = line + strlen(line) - 1;
++
++      while (*line) {
++              if (isspace(*p))
++                      *p-- = '\0';
++              else
++                      break;
++      }
++
++      return line;
++}
++
++#if 0
++static char *parse_word(char **buf)
++{
++      char *word, *next;
++
++      word = *buf;
++      if (*word == '\0')
++              return NULL;
++
++      word = skip_over_blank(word);
++      next = skip_over_word(word);
++      if (*next) {
++              char *end = next - 1;
++              if (*end == '"' || *end == '\'')
++                      *end = '\0';
++              *next++ = '\0';
++      }
++      *buf = next;
++
++      if (*word == '"' || *word == '\'')
++              word++;
++      return word;
++}
++#endif
++
++/*
++ * Start parsing a new line from the cache.
++ *
++ * line starts with "<device" return 1 -> continue parsing line
++ * line starts with "<foo", empty, or # return 0 -> skip line
++ * line starts with other, return -BLKID_ERR_CACHE -> error
++ */
++static int parse_start(char **cp)
++{
++      char *p;
++
++      p = strip_line(*cp);
++
++      /* Skip comment or blank lines.  We can't just NUL the first '#' char,
++       * in case it is inside quotes, or escaped.
++       */
++      if (*p == '\0' || *p == '#')
++              return 0;
++
++      if (!strncmp(p, "<device", 7)) {
++              DBG(DEBUG_READ, printf("found device header: %8s\n", p));
++              p += 7;
++
++              *cp = p;
++              return 1;
++      }
++
++      if (*p == '<')
++              return 0;
++
++      return -BLKID_ERR_CACHE;
++}
++
++/* Consume the remaining XML on the line (cosmetic only) */
++static int parse_end(char **cp)
++{
++      *cp = skip_over_blank(*cp);
++
++      if (!strncmp(*cp, "</device>", 9)) {
++              DBG(DEBUG_READ, printf("found device trailer %9s\n", *cp));
++              *cp += 9;
++              return 0;
++      }
++
++      return -BLKID_ERR_CACHE;
++}
++
++/*
++ * Allocate a new device struct with device name filled in.  Will handle
++ * finding the device on lines of the form:
++ * <device foo=bar>devname</device>
++ * <device>devname<foo>bar</foo></device>
++ */
++static int parse_dev(blkid_cache cache, blkid_dev *dev, char **cp)
++{
++      char *start, *tmp, *end, *name;
++      int ret;
++
++      if ((ret = parse_start(cp)) <= 0)
++              return ret;
++
++      start = tmp = strchr(*cp, '>');
++      if (!start) {
++              DBG(DEBUG_READ,
++                  printf("blkid: short line parsing dev: %s\n", *cp));
++              return -BLKID_ERR_CACHE;
++      }
++      start = skip_over_blank(start + 1);
++      end = skip_over_word(start);
++
++      DBG(DEBUG_READ, printf("device should be %*s\n", end - start, start));
++
++      if (**cp == '>')
++              *cp = end;
++      else
++              (*cp)++;
++
++      *tmp = '\0';
++
++      if (!(tmp = strrchr(end, '<')) || parse_end(&tmp) < 0) {
++              DBG(DEBUG_READ,
++                  printf("blkid: missing </device> ending: %s\n", end));
++      } else if (tmp)
++              *tmp = '\0';
++
++      if (end - start <= 1) {
++              DBG(DEBUG_READ, printf("blkid: empty device name: %s\n", *cp));
++              return -BLKID_ERR_CACHE;
++      }
++
++      name = blkid_strndup(start, end-start);
++      if (name == NULL)
++              return -BLKID_ERR_MEM;
++
++      DBG(DEBUG_READ, printf("found dev %s\n", name));
++
++      if (!(*dev = blkid_get_dev(cache, name, BLKID_DEV_CREATE)))
++              return -BLKID_ERR_MEM;
++
++      free(name);
++      return 1;
++}
++
++/*
++ * Extract a tag of the form NAME="value" from the line.
++ */
++static int parse_token(char **name, char **value, char **cp)
++{
++      char *end;
++
++      if (!name || !value || !cp)
++              return -BLKID_ERR_PARAM;
++
++      if (!(*value = strchr(*cp, '=')))
++              return 0;
++
++      **value = '\0';
++      *name = strip_line(*cp);
++      *value = skip_over_blank(*value + 1);
++
++      if (**value == '"') {
++              end = strchr(*value + 1, '"');
++              if (!end) {
++                      DBG(DEBUG_READ,
++                          printf("unbalanced quotes at: %s\n", *value));
++                      *cp = *value;
++                      return -BLKID_ERR_CACHE;
++              }
++              (*value)++;
++              *end = '\0';
++              end++;
++      } else {
++              end = skip_over_word(*value);
++              if (*end) {
++                      *end = '\0';
++                      end++;
++              }
++      }
++      *cp = end;
++
++      return 1;
++}
++
++/*
++ * Extract a tag of the form <NAME>value</NAME> from the line.
++ */
++/*
++static int parse_xml(char **name, char **value, char **cp)
++{
++      char *end;
++
++      if (!name || !value || !cp)
++              return -BLKID_ERR_PARAM;
++
++      *name = strip_line(*cp);
++
++      if ((*name)[0] != '<' || (*name)[1] == '/')
++              return 0;
++
++      FIXME: finish this.
++}
++*/
++
++/*
++ * Extract a tag from the line.
++ *
++ * Return 1 if a valid tag was found.
++ * Return 0 if no tag found.
++ * Return -ve error code.
++ */
++static int parse_tag(blkid_cache cache, blkid_dev dev, char **cp)
++{
++      char *name;
++      char *value;
++      int ret;
++
++      if (!cache || !dev)
++              return -BLKID_ERR_PARAM;
++
++      if ((ret = parse_token(&name, &value, cp)) <= 0 /* &&
++          (ret = parse_xml(&name, &value, cp)) <= 0 */)
++              return ret;
++
++      /* Some tags are stored directly in the device struct */
++      if (!strcmp(name, "DEVNO")) 
++              dev->bid_devno = STRTOULL(value, 0, 0);
++      else if (!strcmp(name, "PRI"))
++              dev->bid_pri = strtol(value, 0, 0);
++      else if (!strcmp(name, "TIME"))
++              /* FIXME: need to parse a long long eventually */
++              dev->bid_time = strtol(value, 0, 0);
++      else
++              ret = blkid_set_tag(dev, name, value, strlen(value));
++
++      DBG(DEBUG_READ, printf("    tag: %s=\"%s\"\n", name, value));
++
++      return ret < 0 ? ret : 1;
++}
++
++/*
++ * Parse a single line of data, and return a newly allocated dev struct.
++ * Add the new device to the cache struct, if one was read.
++ *
++ * Lines are of the form <device [TAG="value" ...]>/dev/foo</device>
++ *
++ * Returns -ve value on error.
++ * Returns 0 otherwise.
++ * If a valid device was read, *dev_p is non-NULL, otherwise it is NULL
++ * (e.g. comment lines, unknown XML content, etc).
++ */
++static int blkid_parse_line(blkid_cache cache, blkid_dev *dev_p, char *cp)
++{
++      blkid_dev dev;
++      int ret;
++
++      if (!cache || !dev_p)
++              return -BLKID_ERR_PARAM;
++
++      *dev_p = NULL;
++
++      DBG(DEBUG_READ, printf("line: %s\n", cp));
++
++      if ((ret = parse_dev(cache, dev_p, &cp)) <= 0)
++              return ret;
++
++      dev = *dev_p;
++
++      while ((ret = parse_tag(cache, dev, &cp)) > 0) {
++              ;
++      }
++
++      if (dev->bid_type == NULL) {
++              DBG(DEBUG_READ,
++                  printf("blkid: device %s has no TYPE\n",dev->bid_name));
++              blkid_free_dev(dev);
++      }
++
++      DEB_DUMP_DEV(DEBUG_READ, dev);
++
++      return ret;
++}
++
++/*
++ * Parse the specified filename, and return the data in the supplied or
++ * a newly allocated cache struct.  If the file doesn't exist, return a
++ * new empty cache struct.
++ */
++void blkid_read_cache(blkid_cache cache)
++{
++      FILE *file;
++      char buf[4096];
++      int fd, lineno = 0;
++      struct stat st;
++
++      if (!cache)
++              return;
++
++      /*
++       * If the file doesn't exist, then we just return an empty
++       * struct so that the cache can be populated.
++       */
++      if ((fd = open(cache->bic_filename, O_RDONLY)) < 0)
++              return;
++      if (fstat(fd, &st) < 0)
++              goto errout;
++      if ((st.st_mtime == cache->bic_ftime) ||
++          (cache->bic_flags & BLKID_BIC_FL_CHANGED)) {
++              DBG(DEBUG_CACHE, printf("skipping re-read of %s\n",
++                                      cache->bic_filename));
++              goto errout;
++      }
++      
++      DBG(DEBUG_CACHE, printf("reading cache file %s\n",
++                              cache->bic_filename));
++
++      file = fdopen(fd, "r");
++      if (!file)
++              goto errout;
++
++      while (fgets(buf, sizeof(buf), file)) {
++              blkid_dev dev;
++              unsigned int end;
++
++              lineno++;
++              if (buf[0] == 0)
++                      continue;
++              end = strlen(buf) - 1;
++              /* Continue reading next line if it ends with a backslash */
++              while (buf[end] == '\\' && end < sizeof(buf) - 2 &&
++                     fgets(buf + end, sizeof(buf) - end, file)) {
++                      end = strlen(buf) - 1;
++                      lineno++;
++              }
++
++              if (blkid_parse_line(cache, &dev, buf) < 0) {
++                      DBG(DEBUG_READ,
++                          printf("blkid: bad format on line %d\n", lineno));
++                      continue;
++              }
++      }
++      fclose(file);
++
++      /*
++       * Initially we do not need to write out the cache file.
++       */
++      cache->bic_flags &= ~BLKID_BIC_FL_CHANGED;
++      cache->bic_ftime = st.st_mtime;
++
++      return;
++errout:
++      close(fd);
++      return;
++}
++
++#ifdef TEST_PROGRAM
++int main(int argc, char**argv)
++{
++      blkid_cache cache = NULL;
++      int ret;
++
++      blkid_debug_mask = DEBUG_ALL;
++      if (argc > 2) {
++              fprintf(stderr, "Usage: %s [filename]\n"
++                      "Test parsing of the cache (filename)\n", argv[0]);
++              exit(1);
++      }
++      if ((ret = blkid_get_cache(&cache, argv[1])) < 0)
++              fprintf(stderr, "error %d reading cache file %s\n", ret,
++                      argv[1] ? argv[1] : BLKID_CACHE_FILE);
++
++      blkid_put_cache(cache);
++
++      return ret;
++}
++#endif
+diff -Nur busybox-1.00/e2fsprogs/blkid/resolve.c busybox/e2fsprogs/blkid/resolve.c
+--- busybox-1.00/e2fsprogs/blkid/resolve.c     1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/blkid/resolve.c  2005-06-04 08:20:15.000000000 +0200
+@@ -0,0 +1,140 @@
++/*
++ * resolve.c - resolve names and tags into specific devices
++ *
++ * Copyright (C) 2001, 2003 Theodore Ts'o.
++ * Copyright (C) 2001 Andreas Dilger
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the
++ * GNU Lesser General Public License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <stdlib.h>
++#include <fcntl.h>
++#include <string.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include "blkidP.h"
++#include "probe.h"
++
++/*
++ * Find a tagname (e.g. LABEL or UUID) on a specific device.
++ */
++char *blkid_get_tag_value(blkid_cache cache, const char *tagname,
++                        const char *devname)
++{
++      blkid_tag found;
++      blkid_dev dev;
++      blkid_cache c = cache;
++      char *ret = NULL;
++
++      DBG(DEBUG_RESOLVE, printf("looking for %s on %s\n", tagname, devname));
++
++      if (!devname)
++              return NULL;
++
++      if (!cache) {
++              if (blkid_get_cache(&c, NULL) < 0)
++                      return NULL;
++      }
++
++      if ((dev = blkid_get_dev(c, devname, BLKID_DEV_NORMAL)) &&
++          (found = blkid_find_tag_dev(dev, tagname)))
++              ret = blkid_strdup(found->bit_val);
++
++      if (!cache)
++              blkid_put_cache(c);
++
++      return ret;
++}
++
++/*
++ * Locate a device name from a token (NAME=value string), or (name, value)
++ * pair.  In the case of a token, value is ignored.  If the "token" is not
++ * of the form "NAME=value" and there is no value given, then it is assumed
++ * to be the actual devname and a copy is returned.
++ */
++char *blkid_get_devname(blkid_cache cache, const char *token,
++                      const char *value)
++{
++      blkid_dev dev;
++      blkid_cache c = cache;
++      char *t = 0, *v = 0;
++      char *ret = NULL;
++
++      if (!token)
++              return NULL;
++      
++      if (!cache) {
++              if (blkid_get_cache(&c, NULL) < 0)
++                      return NULL;
++      }
++
++      DBG(DEBUG_RESOLVE,
++          printf("looking for %s%s%s %s\n", token, value ? "=" : "",
++                 value ? value : "", cache ? "in cache" : "from disk"));
++
++      if (!value) {
++              if (!strchr(token, '='))
++                      return blkid_strdup(token);
++              blkid_parse_tag_string(token, &t, &v);
++              if (!t || !v)
++                      goto errout;
++              token = t;
++              value = v;
++      }
++
++      dev = blkid_find_dev_with_tag(c, token, value);
++      if (!dev)
++              goto errout;
++
++      ret = blkid_strdup(blkid_dev_devname(dev));
++
++errout:
++      if (t)
++              free(t);
++      if (v)
++              free(v);
++      if (!cache) {
++              blkid_put_cache(c);
++      }
++      return (ret);
++}
++
++#ifdef TEST_PROGRAM
++int main(int argc, char **argv)
++{
++      char *value;
++      blkid_cache cache;
++
++      blkid_debug_mask = DEBUG_ALL;
++      if (argc != 2 && argc != 3) {
++              fprintf(stderr, "Usage:\t%s tagname=value\n"
++                      "\t%s tagname devname\n"
++                      "Find which device holds a given token or\n"
++                      "Find what the value of a tag is in a device\n",
++                      argv[0], argv[0]);
++              exit(1);
++      }
++      if (blkid_get_cache(&cache, "/dev/null") < 0) {
++              fprintf(stderr, "Couldn't get blkid cache\n");
++              exit(1);
++      }
++      
++      if (argv[2]) {
++              value = blkid_get_tag_value(cache, argv[1], argv[2]);
++              printf("%s has tag %s=%s\n", argv[2], argv[1],
++                     value ? value : "<missing>");
++      } else {
++              value = blkid_get_devname(cache, argv[1], NULL);
++              printf("%s has tag %s\n", value ? value : "<none>", argv[1]);
++      }
++      blkid_put_cache(cache);
++      return value ? 0 : 1;
++}
++#endif
+diff -Nur busybox-1.00/e2fsprogs/blkid/save.c busybox/e2fsprogs/blkid/save.c
+--- busybox-1.00/e2fsprogs/blkid/save.c        1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/blkid/save.c     2005-06-04 08:20:15.000000000 +0200
+@@ -0,0 +1,193 @@
++/*
++ * save.c - write the cache struct to disk
++ *
++ * Copyright (C) 2001 by Andreas Dilger
++ * Copyright (C) 2003 Theodore Ts'o
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the
++ * GNU Lesser General Public License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <string.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <sys/types.h>
++#ifdef HAVE_SYS_STAT_H
++#include <sys/stat.h>
++#endif
++#ifdef HAVE_SYS_MKDEV_H
++#include <sys/mkdev.h>
++#endif
++#ifdef HAVE_ERRNO_H
++#include <errno.h>
++#endif
++#include "blkidP.h"
++
++static int save_dev(blkid_dev dev, FILE *file)
++{
++      struct list_head *p;
++
++      if (!dev || dev->bid_name[0] != '/')
++              return 0;
++
++      DBG(DEBUG_SAVE,
++          printf("device %s, type %s\n", dev->bid_name, dev->bid_type));
++
++      fprintf(file,
++              "<device DEVNO=\"0x%04lx\" TIME=\"%lu\"",
++              (unsigned long) dev->bid_devno, dev->bid_time);
++      if (dev->bid_pri)
++              fprintf(file, " PRI=\"%d\"", dev->bid_pri);
++      list_for_each(p, &dev->bid_tags) {
++              blkid_tag tag = list_entry(p, struct blkid_struct_tag, bit_tags);
++              fprintf(file, " %s=\"%s\"", tag->bit_name,tag->bit_val);
++      }
++      fprintf(file, ">%s</device>\n", dev->bid_name);
++
++      return 0;
++}
++
++/*
++ * Write out the cache struct to the cache file on disk.
++ */
++int blkid_flush_cache(blkid_cache cache)
++{
++      struct list_head *p;
++      char *tmp = NULL;
++      const char *opened = NULL;
++      const char *filename;
++      FILE *file = NULL;
++      int fd, ret = 0;
++      struct stat st;
++
++      if (!cache)
++              return -BLKID_ERR_PARAM;
++
++      if (list_empty(&cache->bic_devs) ||
++          !(cache->bic_flags & BLKID_BIC_FL_CHANGED)) {
++              DBG(DEBUG_SAVE, printf("skipping cache file write\n"));
++              return 0;
++      }
++
++      filename = cache->bic_filename ? cache->bic_filename: BLKID_CACHE_FILE;
++
++      /* If we can't write to the cache file, then don't even try */
++      if (((ret = stat(filename, &st)) < 0 && errno != ENOENT) ||
++          (ret == 0 && access(filename, W_OK) < 0)) {
++              DBG(DEBUG_SAVE,
++                  printf("can't write to cache file %s\n", filename));
++              return 0;
++      }
++
++      /*
++       * Try and create a temporary file in the same directory so
++       * that in case of error we don't overwrite the cache file.
++       * If the cache file doesn't yet exist, it isn't a regular
++       * file (e.g. /dev/null or a socket), or we couldn't create
++       * a temporary file then we open it directly.
++       */
++      if (ret == 0 && S_ISREG(st.st_mode)) {
++              tmp = malloc(strlen(filename) + 8);
++              if (tmp) {
++                      sprintf(tmp, "%s-XXXXXX", filename);
++                      fd = mkstemp(tmp);
++                      if (fd >= 0) {
++                              file = fdopen(fd, "w");
++                              opened = tmp;
++                      }
++                      fchmod(fd, 0644);
++              }
++      }
++
++      if (!file) {
++              file = fopen(filename, "w");
++              opened = filename;
++      }
++
++      DBG(DEBUG_SAVE,
++          printf("writing cache file %s (really %s)\n",
++                 filename, opened));
++
++      if (!file) {
++              ret = errno;
++              goto errout;
++      }
++
++      list_for_each(p, &cache->bic_devs) {
++              blkid_dev dev = list_entry(p, struct blkid_struct_dev, bid_devs);
++              if (!dev->bid_type)
++                      continue;
++              if ((ret = save_dev(dev, file)) < 0)
++                      break;
++      }
++
++      if (ret >= 0) {
++              cache->bic_flags &= ~BLKID_BIC_FL_CHANGED;
++              ret = 1;
++      }
++
++      fclose(file);
++      if (opened != filename) {
++              if (ret < 0) {
++                      unlink(opened);
++                      DBG(DEBUG_SAVE,
++                          printf("unlinked temp cache %s\n", opened));
++              } else {
++                      char *backup;
++
++                      backup = malloc(strlen(filename) + 5);
++                      if (backup) {
++                              sprintf(backup, "%s.old", filename);
++                              unlink(backup);
++                              link(filename, backup);
++                              free(backup);
++                      }
++                      rename(opened, filename);
++                      DBG(DEBUG_SAVE,
++                          printf("moved temp cache %s\n", opened));
++              }
++      }
++
++errout:
++      if (tmp)
++              free(tmp);
++      return ret;
++}
++
++#ifdef TEST_PROGRAM
++int main(int argc, char **argv)
++{
++      blkid_cache cache = NULL;
++      int ret;
++
++      blkid_debug_mask = DEBUG_ALL;
++      if (argc > 2) {
++              fprintf(stderr, "Usage: %s [filename]\n"
++                      "Test loading/saving a cache (filename)\n", argv[0]);
++              exit(1);
++      }
++
++      if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) {
++              fprintf(stderr, "%s: error creating cache (%d)\n",
++                      argv[0], ret);
++              exit(1);
++      }
++      if ((ret = blkid_probe_all(cache)) < 0) {
++              fprintf(stderr, "error (%d) probing devices\n", ret);
++              exit(1);
++      }
++      cache->bic_filename = blkid_strdup(argv[1]);
++      
++      if ((ret = blkid_flush_cache(cache)) < 0) {
++              fprintf(stderr, "error (%d) saving cache\n", ret);
++              exit(1);
++      }
++
++      blkid_put_cache(cache);
++
++      return ret;
++}
++#endif
+diff -Nur busybox-1.00/e2fsprogs/blkid/tag.c busybox/e2fsprogs/blkid/tag.c
+--- busybox-1.00/e2fsprogs/blkid/tag.c 1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/blkid/tag.c      2005-06-04 08:20:15.000000000 +0200
+@@ -0,0 +1,340 @@
++/*
++ * tag.c - allocation/initialization/free routines for tag structs
++ *
++ * Copyright (C) 2001 Andreas Dilger
++ * Copyright (C) 2003 Theodore Ts'o
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the
++ * GNU Lesser General Public License.
++ * %End-Header%
++ */
++
++#include <stdlib.h>
++#include <string.h>
++#include <stdio.h>
++
++#include "blkidP.h"
++
++static blkid_tag blkid_new_tag(void)
++{
++      blkid_tag tag;
++
++      if (!(tag = (blkid_tag) calloc(1, sizeof(struct blkid_struct_tag))))
++              return NULL;
++
++      INIT_LIST_HEAD(&tag->bit_tags);
++      INIT_LIST_HEAD(&tag->bit_names);
++
++      return tag;
++}
++
++void blkid_free_tag(blkid_tag tag)
++{
++      if (!tag)
++              return;
++
++      DBG(DEBUG_TAG, printf("    freeing tag %s=%s\n", tag->bit_name,
++                 tag->bit_val ? tag->bit_val : "(NULL)"));
++      DEB_DUMP_TAG(DEBUG_TAG, tag);
++
++      list_del(&tag->bit_tags);       /* list of tags for this device */
++      list_del(&tag->bit_names);      /* list of tags with this type */
++
++      if (tag->bit_name)
++              free(tag->bit_name);
++      if (tag->bit_val)
++              free(tag->bit_val);
++
++      free(tag);
++}
++
++/*
++ * Find the desired tag on a device.  If value is NULL, then the
++ * first such tag is returned, otherwise return only exact tag if found.
++ */
++blkid_tag blkid_find_tag_dev(blkid_dev dev, const char *type)
++{
++      struct list_head *p;
++
++      if (!dev || !type)
++              return NULL;
++
++      list_for_each(p, &dev->bid_tags) {
++              blkid_tag tmp = list_entry(p, struct blkid_struct_tag,
++                                         bit_tags);
++
++              if (!strcmp(tmp->bit_name, type))
++                      return tmp;
++      }
++      return NULL;
++}
++
++/*
++ * Find the desired tag type in the cache.
++ * We return the head tag for this tag type.
++ */
++static blkid_tag blkid_find_head_cache(blkid_cache cache, const char *type)
++{
++      blkid_tag head = NULL, tmp;
++      struct list_head *p;
++
++      if (!cache || !type)
++              return NULL;
++
++      list_for_each(p, &cache->bic_tags) {
++              tmp = list_entry(p, struct blkid_struct_tag, bit_tags);
++              if (!strcmp(tmp->bit_name, type)) {
++                      DBG(DEBUG_TAG,
++                          printf("    found cache tag head %s\n", type));
++                      head = tmp;
++                      break;
++              }
++      }
++      return head;
++}
++
++/*
++ * Set a tag on an existing device.
++ * 
++ * If value is NULL, then delete the tagsfrom the device.
++ */
++int blkid_set_tag(blkid_dev dev, const char *name,
++                const char *value, const int vlength)
++{
++      blkid_tag       t = 0, head = 0;
++      char            *val = 0;
++
++      if (!dev || !name)
++              return -BLKID_ERR_PARAM;
++
++      if (!(val = blkid_strndup(value, vlength)) && value)
++              return -BLKID_ERR_MEM;
++      t = blkid_find_tag_dev(dev, name);
++      if (!value) {
++              if (t)
++                      blkid_free_tag(t);
++      } else if (t) {
++              if (!strcmp(t->bit_val, val)) {
++                      /* Same thing, exit */
++                      free(val);
++                      return 0;
++              }
++              free(t->bit_val);
++              t->bit_val = val;
++      } else {
++              /* Existing tag not present, add to device */
++              if (!(t = blkid_new_tag()))
++                      goto errout;
++              t->bit_name = blkid_strdup(name);
++              t->bit_val = val;
++              t->bit_dev = dev;
++
++              list_add_tail(&t->bit_tags, &dev->bid_tags);
++              
++              if (dev->bid_cache) {
++                      head = blkid_find_head_cache(dev->bid_cache,
++                                                   t->bit_name);
++                      if (!head) {
++                              head = blkid_new_tag();
++                              if (!head)
++                                      goto errout;
++
++                              DBG(DEBUG_TAG,
++                                  printf("    creating new cache tag head %s\n", name));
++                              head->bit_name = blkid_strdup(name);
++                              if (!head->bit_name)
++                                      goto errout;
++                              list_add_tail(&head->bit_tags,
++                                            &dev->bid_cache->bic_tags);
++                      }
++                      list_add_tail(&t->bit_names, &head->bit_names);
++              }
++      }
++      
++      /* Link common tags directly to the device struct */
++      if (!strcmp(name, "TYPE"))
++              dev->bid_type = val;
++      else if (!strcmp(name, "LABEL"))
++              dev->bid_label = val;
++      else if (!strcmp(name, "UUID"))
++              dev->bid_uuid = val;
++              
++      if (dev->bid_cache)
++              dev->bid_cache->bic_flags |= BLKID_BIC_FL_CHANGED;
++      return 0;
++
++errout:
++      if (t)
++              blkid_free_tag(t);
++      else if (val)
++              free(val);
++      if (head)
++              blkid_free_tag(head);
++      return -BLKID_ERR_MEM;
++}
++
++
++/*
++ * Parse a "NAME=value" string.  This is slightly different than
++ * parse_token, because that will end an unquoted value at a space, while
++ * this will assume that an unquoted value is the rest of the token (e.g.
++ * if we are passed an already quoted string from the command-line we don't
++ * have to both quote and escape quote so that the quotes make it to
++ * us).
++ *
++ * Returns 0 on success, and -1 on failure.
++ */
++int blkid_parse_tag_string(const char *token, char **ret_type, char **ret_val)
++{
++      char *name, *value, *cp;
++
++      DBG(DEBUG_TAG, printf("trying to parse '%s' as a tag\n", token));
++
++      if (!token || !(cp = strchr(token, '=')))
++              return -1;
++
++      name = blkid_strdup(token);
++      if (!name)
++              return -1;
++      value = name + (cp - token);
++      *value++ = '\0';
++      if (*value == '"' || *value == '\'') {
++              char c = *value++;
++              if (!(cp = strrchr(value, c)))
++                      goto errout; /* missing closing quote */
++              *cp = '\0';
++      }
++      value = blkid_strdup(value);
++      if (!value)
++              goto errout;
++
++      *ret_type = name;
++      *ret_val = value;
++
++      return 0;
++
++errout:
++      free(name);
++      return -1;
++}
++
++/*
++ * Tag iteration routines for the public libblkid interface.
++ *
++ * These routines do not expose the list.h implementation, which are a
++ * contamination of the namespace, and which force us to reveal far, far
++ * too much of our internal implemenation.  I'm not convinced I want
++ * to keep list.h in the long term, anyway.  It's fine for kernel
++ * programming, but performance is not the #1 priority for this
++ * library, and I really don't like the tradeoff of type-safety for
++ * performance for this application.  [tytso:20030125.2007EST]
++ */
++
++/*
++ * This series of functions iterate over all tags in a device
++ */
++#define TAG_ITERATE_MAGIC     0x01a5284c
++      
++struct blkid_struct_tag_iterate {
++      int                     magic;
++      blkid_dev               dev;
++      struct list_head        *p;
++};
++
++extern blkid_tag_iterate blkid_tag_iterate_begin(blkid_dev dev)
++{
++      blkid_tag_iterate       iter;
++
++      iter = malloc(sizeof(struct blkid_struct_tag_iterate));
++      if (iter) {
++              iter->magic = TAG_ITERATE_MAGIC;
++              iter->dev = dev;
++              iter->p = dev->bid_tags.next;
++      }
++      return (iter);
++}
++
++/*
++ * Return 0 on success, -1 on error
++ */
++extern int blkid_tag_next(blkid_tag_iterate iter,
++                        const char **type, const char **value)
++{
++      blkid_tag tag;
++      
++      *type = 0;
++      *value = 0;
++      if (!iter || iter->magic != TAG_ITERATE_MAGIC ||
++          iter->p == &iter->dev->bid_tags)
++              return -1;
++      tag = list_entry(iter->p, struct blkid_struct_tag, bit_tags);
++      *type = tag->bit_name;
++      *value = tag->bit_val;
++      iter->p = iter->p->next;
++      return 0;
++}
++
++extern void blkid_tag_iterate_end(blkid_tag_iterate iter)
++{
++      if (!iter || iter->magic != TAG_ITERATE_MAGIC)
++              return;
++      iter->magic = 0;
++      free(iter);
++}
++
++/*
++ * This function returns a device which matches a particular
++ * type/value pair.  If there is more than one device that matches the
++ * search specification, it returns the one with the highest priority
++ * value.  This allows us to give preference to EVMS or LVM devices.
++ *
++ * XXX there should also be an interface which uses an iterator so we
++ * can get all of the devices which match a type/value search parameter.
++ */
++extern blkid_dev blkid_find_dev_with_tag(blkid_cache cache,
++                                       const char *type,
++                                       const char *value)
++{
++      blkid_tag       head;
++      blkid_dev       dev;
++      int             pri;
++      struct list_head *p;
++
++      if (!cache || !type || !value)
++              return NULL;
++
++      blkid_read_cache(cache);
++      
++      DBG(DEBUG_TAG, printf("looking for %s=%s in cache\n", type, value));
++      
++try_again:
++      pri = -1;
++      dev = 0;
++      head = blkid_find_head_cache(cache, type);
++
++      if (head) {
++              list_for_each(p, &head->bit_names) {
++                      blkid_tag tmp = list_entry(p, struct blkid_struct_tag, 
++                                                 bit_names);
++
++                      if (!strcmp(tmp->bit_val, value) &&
++                          tmp->bit_dev->bid_pri > pri) {
++                              dev = tmp->bit_dev;
++                              pri = dev->bid_pri;
++                      }
++              }
++      }
++      if (dev && !(dev->bid_flags & BLKID_BID_FL_VERIFIED)) {
++              dev = blkid_verify(cache, dev);
++              if (dev && (dev->bid_flags & BLKID_BID_FL_VERIFIED))
++                      goto try_again;
++      }
++
++      if (!dev && !(cache->bic_flags & BLKID_BIC_FL_PROBED)) {
++              if (blkid_probe_all(cache) < 0)
++                      return NULL;
++              goto try_again;
++      }
++      return dev;
++}
+diff -Nur busybox-1.00/e2fsprogs/blkid/version.c busybox/e2fsprogs/blkid/version.c
+--- busybox-1.00/e2fsprogs/blkid/version.c     1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/blkid/version.c  2005-06-04 08:20:15.000000000 +0200
+@@ -0,0 +1,49 @@
++/*
++ * version.c --- Return the version of the blkid library
++ *
++ * Copyright (C) 2004 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <string.h>
++#include <stdio.h>
++#include <ctype.h>
++
++#include "blkid.h"
++#include "../../version.h"
++
++static const char *lib_version = E2FSPROGS_VERSION;
++static const char *lib_date = E2FSPROGS_DATE;
++
++int blkid_parse_version_string(const char *ver_string)
++{
++      const char *cp;
++      int version = 0;
++
++      for (cp = ver_string; *cp; cp++) {
++              if (*cp == '.')
++                      continue;
++              if (!isdigit(*cp))
++                      break;
++              version = (version * 10) + (*cp - '0');
++      }
++      return version;
++}
++
++int blkid_get_library_version(const char **ver_string,
++                             const char **date_string)
++{
++      if (ver_string)
++              *ver_string = lib_version;
++      if (date_string)
++              *date_string = lib_date;
++
++      return blkid_parse_version_string(lib_version);
++}
+diff -Nur busybox-1.00/e2fsprogs/chattr.c busybox/e2fsprogs/chattr.c
+--- busybox-1.00/e2fsprogs/chattr.c    1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/chattr.c 2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,225 @@
++/*
++ * chattr.c           - Change file attributes on an ext2 file system
++ *
++ * Copyright (C) 1993, 1994  Remy Card <card@masi.ibp.fr>
++ *                           Laboratoire MASI, Institut Blaise Pascal
++ *                           Universite Pierre et Marie Curie (Paris VI)
++ *
++ * This file can be redistributed under the terms of the GNU General
++ * Public License
++ */
++
++/*
++ * History:
++ * 93/10/30   - Creation
++ * 93/11/13   - Replace stat() calls by lstat() to avoid loops
++ * 94/02/27   - Integrated in Ted's distribution
++ * 98/12/29   - Ignore symlinks when working recursively (G M Sipe)
++ * 98/12/29   - Display version info only when -V specified (G M Sipe)
++ */
++
++#include <sys/types.h>
++#include <dirent.h>
++#include <fcntl.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include <errno.h>
++#include <sys/param.h>
++#include <sys/stat.h>
++#include <ext2fs/ext2_fs.h>
++
++#ifdef __GNUC__
++# define EXT2FS_ATTR(x) __attribute__(x)
++#else
++# define EXT2FS_ATTR(x)
++#endif
++
++#include "e2fsbb.h"
++#include "e2p/e2p.h"
++
++#define OPT_ADD 1
++#define OPT_REM 2
++#define OPT_SET 4
++#define OPT_SET_VER 8
++static int flags;
++static int recursive;
++
++static unsigned long version;
++
++static unsigned long af;
++static unsigned long rf;
++static unsigned long sf;
++
++#ifdef CONFIG_LFS
++# define LSTAT lstat64
++# define STRUCT_STAT struct stat64
++#else
++# define LSTAT lstat
++# define STRUCT_STAT struct stat
++#endif
++
++struct flags_char {
++      unsigned long flag;
++      char optchar;
++};
++
++static const struct flags_char flags_array[] = {
++      { EXT2_NOATIME_FL,      'A' },
++      { EXT2_SYNC_FL,         'S' },
++      { EXT2_DIRSYNC_FL,      'D' },
++      { EXT2_APPEND_FL,       'a' },
++      { EXT2_COMPR_FL,        'c' },
++      { EXT2_NODUMP_FL,       'd' },
++      { EXT2_IMMUTABLE_FL,    'i' },
++      { EXT3_JOURNAL_DATA_FL, 'j' },
++      { EXT2_SECRM_FL,        's' },
++      { EXT2_UNRM_FL,         'u' },
++      { EXT2_NOTAIL_FL,       't' },
++      { EXT2_TOPDIR_FL,       'T' },
++      { 0, 0 }
++};
++
++static unsigned long get_flag(char c)
++{
++      const struct flags_char *fp;
++      for (fp = flags_array; fp->flag; fp++)
++              if (fp->optchar == c)
++                      return fp->flag;
++      bb_show_usage();
++      return 0;
++}
++
++static int decode_arg(char *arg)
++{
++      unsigned long *fl;
++      char opt = *arg++;
++
++      if (opt == '-') {
++              flags |= OPT_REM;
++              fl = &rf;
++      } else if (opt == '+') {
++              flags |= OPT_ADD;
++              fl = &af;
++      } else if (opt == '=') {
++              flags |= OPT_SET;
++              fl = &sf;
++      } else
++              return EOF;
++
++      for (; *arg ; ++arg)
++              (*fl) |= get_flag(*arg);
++
++      return 1;
++}
++
++static int chattr_dir_proc(const char *, struct dirent *, void *);
++
++static void change_attributes(const char * name)
++{
++      unsigned long fsflags;
++      STRUCT_STAT     st;
++
++      if (LSTAT(name, &st) == -1) {
++              bb_error_msg("stat %s failed", name);
++              return;
++      }
++      if (S_ISLNK(st.st_mode) && recursive)
++              return;
++
++      /* Don't try to open device files, fifos etc.  We probably
++       * ought to display an error if the file was explicitly given
++       * on the command line (whether or not recursive was
++       * requested).  */
++      if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode) && !S_ISDIR(st.st_mode))
++              return;
++
++      if (flags & OPT_SET_VER)
++              if (fsetversion(name, version) == -1)
++                      bb_error_msg("setting version on %s", name);
++
++      if (flags & OPT_SET) {
++              fsflags = sf;
++      } else {
++              if (fgetflags(name, &fsflags) == -1) {
++                      bb_error_msg("reading flags on %s", name);
++                      goto skip_setflags;
++              }
++              if (flags & OPT_REM)
++                      fsflags &= ~rf;
++              if (flags & OPT_ADD)
++                      fsflags |= af;
++              if (!S_ISDIR(st.st_mode))
++                      fsflags &= ~EXT2_DIRSYNC_FL;
++      }
++      if (fsetflags(name, fsflags) == -1)
++              bb_error_msg("setting flags on %s", name);
++
++skip_setflags:
++      if (S_ISDIR(st.st_mode) && recursive)
++              iterate_on_dir(name, chattr_dir_proc, NULL);
++}
++
++static int chattr_dir_proc(const char *dir_name, struct dirent *de, 
++                           void *private EXT2FS_ATTR((unused)))
++{
++      /*if (strcmp(de->d_name, ".") && strcmp(de->d_name, "..")) {*/
++      if (de->d_name[0] == '.' && (de->d_name[1] == '\0' || \
++         (de->d_name[1] == '.' && de->d_name[2] == '\0'))) {
++              char *path = concat_subpath_file(dir_name, de->d_name);
++              if (path) {
++                      change_attributes(path);
++                      free(path);
++              }
++      }
++      return 0;
++}
++
++int chattr_main(int argc, char **argv)
++{
++      int i;
++      char *arg;
++
++      /* parse the args */
++      for (i = 1; i < argc; ++i) {
++              arg = argv[i];
++
++              /* take care of -R and -v <version> */
++              if (arg[0] == '-') {
++                      if (arg[1] == 'R' && arg[2] == '\0') {
++                              recursive = 1;
++                              continue;
++                      } else if (arg[1] == 'v' && arg[2] == '\0') {
++                              char *tmp;
++                              ++i;
++                              if (i >= argc)
++                                      bb_show_usage();
++                              version = strtol(argv[i], &tmp, 0);
++                              if (*tmp)
++                                      bb_error_msg_and_die("bad version '%s'", arg);
++                              flags |= OPT_SET_VER;
++                              continue;
++                      }
++              }
++
++              if (decode_arg(arg) == EOF)
++                      break;
++      }
++
++      /* run sanity checks on all the arguments given us */
++      if (i >= argc)
++              bb_show_usage();
++      if ((flags & OPT_SET) && ((flags & OPT_ADD) || (flags & OPT_REM)))
++              bb_error_msg_and_die("= is incompatible with - and +");
++      if ((rf & af) != 0)
++              bb_error_msg_and_die("Can't set and unset a flag");
++      if (!flags)
++              bb_error_msg_and_die("Must use '-v', =, - or +");
++
++      /* now run chattr on all the files passed to us */
++      while (i < argc)
++              change_attributes(argv[i++]);
++
++      return EXIT_SUCCESS;
++}
+diff -Nur busybox-1.00/e2fsprogs/e2fsbb.h busybox/e2fsprogs/e2fsbb.h
+--- busybox-1.00/e2fsprogs/e2fsbb.h    1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/e2fsbb.h 2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,40 @@
++/*
++ * File: e2fsbb.h
++ *
++ * Redefine a bunch of e2fsprogs stuff to use busybox routines
++ * instead.  This makes upgrade between e2fsprogs versions easy.
++ */
++
++#ifndef __E2FSBB_H__
++#define __E2FSBB_H__ 1
++
++#include "libbb.h"
++
++/* version we've last synced against */
++#define E2FSPROGS_VERSION "1.37"
++#define E2FSPROGS_DATE "21-Mar-2005"
++
++/* make sure com_err.h isnt included before us */
++#ifdef __COM_ERR_H__
++#error You should not have included com_err.h !
++#endif
++#define __COM_ERR_H__
++
++/* com_err crap */
++#define com_err(w, c, fmt, args...) bb_error_msg(fmt, ## args)
++typedef long errcode_t;
++#define ERRCODE_RANGE 8
++#define error_message(code) strerror((int) (code & ((1<<ERRCODE_RANGE)-1)))
++#define initialize_ext2_error_table(x)
++
++/* NLS crap */
++#define _(x) x
++#define N_(x) x
++#define P_(singular, plural, n) ((n) == 1 ? (singular) : (plural))
++
++/* misc crap */
++#define fatal_error(msg, err) bb_error_msg_and_die(msg)
++#define usage() bb_show_usage()
++#define perror(msg) bb_perror_msg(msg)
++
++#endif /* __E2FSBB_H__ */
+diff -Nur busybox-1.00/e2fsprogs/e2p/e2p.h busybox/e2fsprogs/e2p/e2p.h
+--- busybox-1.00/e2fsprogs/e2p/e2p.h   1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/e2p/e2p.h        2005-06-04 08:20:15.000000000 +0200
+@@ -0,0 +1,59 @@
++#include <sys/types.h>                /* Needed by dirent.h on netbsd */
++#include <stdio.h>
++#include <dirent.h>
++
++#include <ext2fs/ext2_fs.h>
++
++#define E2P_FEATURE_COMPAT    0
++#define E2P_FEATURE_INCOMPAT  1
++#define E2P_FEATURE_RO_INCOMPAT       2
++
++
++/* `options' for print_flags() */
++
++#define PFOPT_LONG  1 /* Must be 1 for compatibility with `int long_format'. */
++
++/*int fgetversion (const char * name, unsigned long * version);*/
++/*int fsetversion (const char * name, unsigned long version);*/
++int fgetsetversion(const char * name, unsigned long * get_version, unsigned long set_version);
++#define fgetversion(name, version) fgetsetversion(name, version, 0)
++#define fsetversion(name, version) fgetsetversion(name, NULL, version)
++
++/*int fgetflags (const char * name, unsigned long * flags);*/
++/*int fsetflags (const char * name, unsigned long flags);*/
++int fgetsetflags(const char * name, unsigned long * get_flags, unsigned long set_flags);
++#define fgetflags(name, flags) fgetsetflags(name, flags, 0)
++#define fsetflags(name, flags) fgetsetflags(name, NULL, flags)
++
++int getflags (int fd, unsigned long * flags);
++int getversion (int fd, unsigned long * version);
++int iterate_on_dir (const char * dir_name,
++                  int (*func) (const char *, struct dirent *, void *),
++                  void * private);
++void list_super(struct ext2_super_block * s);
++void list_super2(struct ext2_super_block * s, FILE *f);
++void print_fs_errors (FILE * f, unsigned short errors);
++void print_flags (FILE * f, unsigned long flags, unsigned options);
++void print_fs_state (FILE * f, unsigned short state);
++int setflags (int fd, unsigned long flags);
++int setversion (int fd, unsigned long version);
++
++const char *e2p_feature2string(int compat, unsigned int mask);
++int e2p_string2feature(char *string, int *compat, unsigned int *mask);
++int e2p_edit_feature(const char *str, __u32 *compat_array, __u32 *ok_array);
++
++int e2p_is_null_uuid(void *uu);
++void e2p_uuid_to_str(void *uu, char *out);
++const char *e2p_uuid2str(void *uu);
++
++const char *e2p_hash2string(int num);
++int e2p_string2hash(char *string);
++
++const char *e2p_mntopt2string(unsigned int mask);
++int e2p_string2mntopt(char *string, unsigned int *mask);
++int e2p_edit_mntopts(const char *str, __u32 *mntopts, __u32 ok);
++
++unsigned long parse_num_blocks(const char *arg, int log_block_size);
++
++char *e2p_os2string(int os_type);
++int e2p_string2os(char *str);
+diff -Nur busybox-1.00/e2fsprogs/e2p/feature.c busybox/e2fsprogs/e2p/feature.c
+--- busybox-1.00/e2fsprogs/e2p/feature.c       1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/e2p/feature.c    2005-06-04 08:20:15.000000000 +0200
+@@ -0,0 +1,190 @@
++/*
++ * feature.c --- convert between features and strings
++ * 
++ * Copyright (C) 1999  Theodore Ts'o <tytso@mit.edu>
++ * 
++ * This file can be redistributed under the terms of the GNU Library General
++ * Public License
++ * 
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <ctype.h>
++#include <errno.h>
++
++#include "e2p.h"
++
++struct feature {
++      int             compat;
++      unsigned int    mask;
++      const char      *string;
++};
++
++static struct feature feature_list[] = {
++      {       E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_PREALLOC,
++                      "dir_prealloc" },
++      {       E2P_FEATURE_COMPAT, EXT3_FEATURE_COMPAT_HAS_JOURNAL,
++                      "has_journal" },
++      {       E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_IMAGIC_INODES,
++                      "imagic_inodes" },
++      {       E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_EXT_ATTR,
++                      "ext_attr" },
++      {       E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_INDEX,
++                      "dir_index" },
++      {       E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_RESIZE_INODE,
++                      "resize_inode" },
++      {       E2P_FEATURE_RO_INCOMPAT, EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER,
++                      "sparse_super" },
++      {       E2P_FEATURE_RO_INCOMPAT, EXT2_FEATURE_RO_COMPAT_LARGE_FILE,
++                      "large_file" },
++      {       E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_COMPRESSION,
++                      "compression" },
++      {       E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_FILETYPE,
++                      "filetype" },
++      {       E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_RECOVER,
++                      "needs_recovery" },
++      {       E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_JOURNAL_DEV,
++                      "journal_dev" },
++      {       E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_EXTENTS,
++                      "extents" },
++      {       E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_META_BG,
++                      "meta_bg" },
++      {       0, 0, 0 },
++};
++
++const char *e2p_feature2string(int compat, unsigned int mask)
++{
++      struct feature  *f;
++      static char buf[20];
++      char    fchar;
++      int     fnum;
++
++      for (f = feature_list; f->string; f++) {
++              if ((compat == f->compat) &&
++                  (mask == f->mask))
++                      return f->string;
++      }
++      switch (compat) {
++      case  E2P_FEATURE_COMPAT:
++              fchar = 'C';
++              break;
++      case E2P_FEATURE_INCOMPAT:
++              fchar = 'I';
++              break;
++      case E2P_FEATURE_RO_INCOMPAT:
++              fchar = 'R';
++              break;
++      default:
++              fchar = '?';
++              break;
++      }
++      for (fnum = 0; mask >>= 1; fnum++);
++      sprintf(buf, "FEATURE_%c%d", fchar, fnum);
++      return buf;
++}
++
++int e2p_string2feature(char *string, int *compat_type, unsigned int *mask)
++{
++      struct feature  *f;
++      char            *eptr;
++      int             num;
++
++      for (f = feature_list; f->string; f++) {
++              if (!strcasecmp(string, f->string)) {
++                      *compat_type = f->compat;
++                      *mask = f->mask;
++                      return 0;
++              }
++      }
++      if (strncasecmp(string, "FEATURE_", 8))
++              return 1;
++
++      switch (string[8]) {
++      case 'c':
++      case 'C':
++              *compat_type = E2P_FEATURE_COMPAT;
++              break;
++      case 'i':
++      case 'I':
++              *compat_type = E2P_FEATURE_INCOMPAT;
++              break;
++      case 'r':
++      case 'R':
++              *compat_type = E2P_FEATURE_RO_INCOMPAT;
++              break;
++      default:
++              return 1;
++      }
++      if (string[9] == 0)
++              return 1;
++      num = strtol(string+9, &eptr, 10);
++      if (num > 32 || num < 0)
++              return 1;
++      if (*eptr)
++              return 1;
++      *mask = 1 << num;
++      return 0;
++}
++
++static char *skip_over_blanks(char *cp)
++{
++      while (*cp && isspace(*cp))
++              cp++;
++      return cp;
++}
++
++static char *skip_over_word(char *cp)
++{
++      while (*cp && !isspace(*cp) && *cp != ',')
++              cp++;
++      return cp;
++}
++
++/*
++ * Edit a feature set array as requested by the user.  The ok_array,
++ * if set, allows the application to limit what features the user is
++ * allowed to set or clear using this function.
++ */
++int e2p_edit_feature(const char *str, __u32 *compat_array, __u32 *ok_array)
++{
++      char    *cp, *buf, *next;
++      int     neg;
++      unsigned int    mask;
++      int             compat_type;
++
++      buf = malloc(strlen(str)+1);
++      if (!buf)
++              return 1;
++      strcpy(buf, str);
++      cp = buf;
++      while (cp && *cp) {
++              neg = 0;
++              cp = skip_over_blanks(cp);
++              next = skip_over_word(cp);
++              if (*next == 0)
++                      next = 0;
++              else
++                      *next = 0;
++              switch (*cp) {
++              case '-':
++              case '^':
++                      neg++;
++              case '+':
++                      cp++;
++                      break;
++              }
++              if (e2p_string2feature(cp, &compat_type, &mask))
++                      return 1;
++              if (ok_array && !(ok_array[compat_type] & mask))
++                      return 1;
++              if (neg)
++                      compat_array[compat_type] &= ~mask;
++              else
++                      compat_array[compat_type] |= mask;
++              cp = next ? next+1 : 0;
++      }
++      return 0;
++}
++
+diff -Nur busybox-1.00/e2fsprogs/e2p/fgetsetflags.c busybox/e2fsprogs/e2p/fgetsetflags.c
+--- busybox-1.00/e2fsprogs/e2p/fgetsetflags.c  1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/e2p/fgetsetflags.c       2005-06-04 08:20:15.000000000 +0200
+@@ -0,0 +1,69 @@
++/*
++ * fgetflags.c                - Get a file flags on an ext2 file system
++ * fsetflags.c                - Set a file flags on an ext2 file system
++ *
++ * Copyright (C) 1993, 1994  Remy Card <card@masi.ibp.fr>
++ *                           Laboratoire MASI, Institut Blaise Pascal
++ *                           Universite Pierre et Marie Curie (Paris VI)
++ *
++ * This file can be redistributed under the terms of the GNU Library General
++ * Public License
++ */
++
++/*
++ * History:
++ * 93/10/30   - Creation
++ */
++
++#if HAVE_ERRNO_H
++#include <errno.h>
++#endif
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <sys/types.h>
++#include <sys/stat.h>
++#if HAVE_EXT2_IOCTLS
++#include <fcntl.h>
++#include <sys/ioctl.h>
++#endif
++
++#include "e2p.h"
++
++#ifdef O_LARGEFILE
++#define OPEN_FLAGS (O_RDONLY|O_NONBLOCK|O_LARGEFILE)
++#else
++#define OPEN_FLAGS (O_RDONLY|O_NONBLOCK)
++#endif
++
++int fgetsetflags (const char * name, unsigned long * get_flags, unsigned long set_flags)
++{
++#if HAVE_EXT2_IOCTLS
++      struct stat buf;
++      int fd, r, f, save_errno = 0;
++
++      if (!stat(name, &buf) &&
++          !S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode)) {
++              goto notsupp;
++      }
++      fd = open (name, OPEN_FLAGS);
++      if (fd == -1)
++              return -1;
++      if (!get_flags) {
++              f = (int) set_flags;
++              r = ioctl (fd, EXT2_IOC_SETFLAGS, &f);
++      } else {
++              r = ioctl (fd, EXT2_IOC_GETFLAGS, &f);
++              *get_flags = f;
++      }
++      if (r == -1)
++              save_errno = errno;
++      close (fd);
++      if (save_errno)
++              errno = save_errno;
++      return r;
++#endif /* HAVE_EXT2_IOCTLS */
++notsupp:
++      errno = EOPNOTSUPP;
++      return -1;
++}
+diff -Nur busybox-1.00/e2fsprogs/e2p/fgetsetversion.c busybox/e2fsprogs/e2p/fgetsetversion.c
+--- busybox-1.00/e2fsprogs/e2p/fgetsetversion.c        1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/e2p/fgetsetversion.c     2005-06-04 08:20:15.000000000 +0200
+@@ -0,0 +1,69 @@
++/*
++ * fgetversion.c      - Get a file version on an ext2 file system
++ * fsetversion.c      - Set a file version on an ext2 file system
++ *
++ *
++ * Copyright (C) 1993, 1994  Remy Card <card@masi.ibp.fr>
++ *                           Laboratoire MASI, Institut Blaise Pascal
++ *                           Universite Pierre et Marie Curie (Paris VI)
++ *
++ * This file can be redistributed under the terms of the GNU Library General
++ * Public License
++ */
++
++/*
++ * History:
++ * 93/10/30   - Creation
++ */
++
++#if HAVE_ERRNO_H
++#include <errno.h>
++#endif
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <fcntl.h>
++#include <sys/ioctl.h>
++
++#include "e2p.h"
++
++#ifdef O_LARGEFILE
++#define OPEN_FLAGS (O_RDONLY|O_NONBLOCK|O_LARGEFILE)
++#else
++#define OPEN_FLAGS (O_RDONLY|O_NONBLOCK)
++#endif
++
++/* 
++   To do fsetversion:     unsigned long *ptr_version must be set to NULL.
++                      and unsigned long version must be set to a value   
++   To do fgetversion:     unsigned long *ptr_version must NOT be set to NULL
++                      and unsigned long version is ignored.
++      TITO.
++*/
++
++int fgetsetversion (const char * name, unsigned long * get_version, unsigned long set_version)
++{
++#if HAVE_EXT2_IOCTLS
++      int fd, r, ver, save_errno = 0;
++
++      fd = open (name, OPEN_FLAGS);
++      if (fd == -1)
++              return -1;
++      if (!get_version) {
++              ver = (int) set_version;
++              r = ioctl (fd, EXT2_IOC_SETVERSION, &ver);
++      } else {
++              r = ioctl (fd, EXT2_IOC_GETVERSION, &ver);
++              *get_version = ver;
++      }
++      if (r == -1)
++              save_errno = errno;
++      close (fd);
++      if (save_errno)
++              errno = save_errno;
++      return r;
++#else /* ! HAVE_EXT2_IOCTLS */
++      errno = EOPNOTSUPP;
++      return -1;
++#endif /* ! HAVE_EXT2_IOCTLS */
++}
+diff -Nur busybox-1.00/e2fsprogs/e2p/hashstr.c busybox/e2fsprogs/e2p/hashstr.c
+--- busybox-1.00/e2fsprogs/e2p/hashstr.c       1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/e2p/hashstr.c    2005-06-04 08:20:15.000000000 +0200
+@@ -0,0 +1,70 @@
++/*
++ * feature.c --- convert between features and strings
++ * 
++ * Copyright (C) 1999  Theodore Ts'o <tytso@mit.edu>
++ * 
++ * This file can be redistributed under the terms of the GNU Library General
++ * Public License
++ * 
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <ctype.h>
++#include <errno.h>
++
++#include "e2p.h"
++
++struct hash {
++      int             num;
++      const char      *string;
++};
++
++static struct hash hash_list[] = {
++      {       EXT2_HASH_LEGACY,       "legacy" },
++      {       EXT2_HASH_HALF_MD4,     "half_md4" },
++      {       EXT2_HASH_TEA,          "tea" },
++      {       0, 0 },
++};
++
++const char *e2p_hash2string(int num)
++{
++      struct hash  *p;
++      static char buf[20];
++
++      for (p = hash_list; p->string; p++) {
++              if (num == p->num)
++                      return p->string;
++      }
++      sprintf(buf, "HASHALG_%d", num);
++      return buf;
++}
++
++/*
++ * Returns the hash algorithm, or -1 on error
++ */
++int e2p_string2hash(char *string)
++{
++      struct hash     *p;
++      char            *eptr;
++      int             num;
++
++      for (p = hash_list; p->string; p++) {
++              if (!strcasecmp(string, p->string)) {
++                      return p->num;
++              }
++      }
++      if (strncasecmp(string, "HASHALG_", 8))
++              return -1;
++
++      if (string[8] == 0)
++              return -1;
++      num = strtol(string+8, &eptr, 10);
++      if (num > 255 || num < 0)
++              return -1;
++      if (*eptr)
++              return -1;
++      return num;
++}
++
+diff -Nur busybox-1.00/e2fsprogs/e2p/iod.c busybox/e2fsprogs/e2p/iod.c
+--- busybox-1.00/e2fsprogs/e2p/iod.c   1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/e2p/iod.c        2005-06-04 08:20:15.000000000 +0200
+@@ -0,0 +1,51 @@
++/*
++ * iod.c              - Iterate a function on each entry of a directory
++ *
++ * Copyright (C) 1993, 1994  Remy Card <card@masi.ibp.fr>
++ *                           Laboratoire MASI, Institut Blaise Pascal
++ *                           Universite Pierre et Marie Curie (Paris VI)
++ *
++ * This file can be redistributed under the terms of the GNU Library General
++ * Public License
++ */
++
++/*
++ * History:
++ * 93/10/30   - Creation
++ */
++
++#include "e2p.h"
++#include <unistd.h>
++#include <stdlib.h>
++#include <string.h>
++
++int iterate_on_dir (const char * dir_name,
++                  int (*func) (const char *, struct dirent *, void *),
++                  void * private)
++{
++      DIR * dir;
++      struct dirent *de, *dep;
++      int     max_len, len;
++
++      max_len = PATH_MAX + sizeof(struct dirent);
++      de = (struct dirent *)xmalloc(max_len+1);
++      memset(de, 0, max_len+1);
++
++      dir = opendir (dir_name);
++      if (dir == NULL) {
++              free(de);
++              return -1;
++      }
++      while ((dep = readdir (dir))) {
++              len = sizeof(struct dirent);
++              if (len < dep->d_reclen)
++                      len = dep->d_reclen;
++              if (len > max_len)
++                      len = max_len;
++              memcpy(de, dep, len);
++              (*func) (dir_name, de, private);
++      }
++      free(de);
++      closedir(dir);
++      return 0;
++}
+diff -Nur busybox-1.00/e2fsprogs/e2p/ls.c busybox/e2fsprogs/e2p/ls.c
+--- busybox-1.00/e2fsprogs/e2p/ls.c    1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/e2p/ls.c 2005-06-04 08:20:15.000000000 +0200
+@@ -0,0 +1,276 @@
++/*
++ * ls.c                       - List the contents of an ext2fs superblock
++ *
++ * Copyright (C) 1992, 1993, 1994  Remy Card <card@masi.ibp.fr>
++ *                                 Laboratoire MASI, Institut Blaise Pascal
++ *                                 Universite Pierre et Marie Curie (Paris VI)
++ *
++ * Copyright (C) 1995, 1996, 1997  Theodore Ts'o <tytso@mit.edu>
++ * 
++ * This file can be redistributed under the terms of the GNU Library General
++ * Public License
++ */
++
++#include <stdio.h>
++#include <sys/types.h>
++#include <string.h>
++#include <grp.h>
++#include <pwd.h>
++#include <time.h>
++
++#include "e2p.h"
++
++static void print_user (unsigned short uid, FILE *f)
++{
++      struct passwd *pw;
++
++      fprintf(f, "%u ", uid);
++      pw = getpwuid (uid);
++      if (pw == NULL)
++              fprintf(f, "(user unknown)\n");
++      else
++              fprintf(f, "(user %s)\n", pw->pw_name);
++}
++
++static void print_group (unsigned short gid, FILE *f)
++{
++      struct group *gr;
++
++      fprintf(f, "%u ", gid);
++      gr = getgrgid (gid);
++      if (gr == NULL)
++              fprintf(f, "(group unknown)\n");
++      else
++              fprintf(f, "(group %s)\n", gr->gr_name);
++}
++
++#define MONTH_INT (86400 * 30)
++#define WEEK_INT (86400 * 7)
++#define DAY_INT       (86400)
++#define HOUR_INT (60 * 60)
++#define MINUTE_INT (60)
++
++static const char *interval_string(unsigned int secs)
++{
++      static char buf[256], tmp[80];
++      int             hr, min, num;
++
++      buf[0] = 0;
++
++      if (secs == 0)
++              return "<none>";
++
++      if (secs >= MONTH_INT) {
++              num = secs / MONTH_INT;
++              secs -= num*MONTH_INT;
++              sprintf(buf, "%d month%s", num, (num>1) ? "s" : "");
++      }
++      if (secs >= WEEK_INT) {
++              num = secs / WEEK_INT;
++              secs -= num*WEEK_INT;
++              sprintf(tmp, "%s%d week%s", buf[0] ? ", " : "",
++                      num, (num>1) ? "s" : "");
++              strcat(buf, tmp);
++      }
++      if (secs >= DAY_INT) {
++              num = secs / DAY_INT;
++              secs -= num*DAY_INT;
++              sprintf(tmp, "%s%d day%s", buf[0] ? ", " : "",
++                      num, (num>1) ? "s" : "");
++              strcat(buf, tmp);
++      }
++      if (secs > 0) {
++              hr = secs / HOUR_INT;
++              secs -= hr*HOUR_INT;
++              min = secs / MINUTE_INT;
++              secs -= min*MINUTE_INT;
++              sprintf(tmp, "%s%d:%02d:%02d", buf[0] ? ", " : "",
++                      hr, min, secs);
++              strcat(buf, tmp);
++      }
++      return buf;
++}
++
++static void print_features(struct ext2_super_block * s, FILE *f)
++{
++#ifdef EXT2_DYNAMIC_REV
++      int     i, j, printed=0;
++      __u32   *mask = &s->s_feature_compat, m;
++
++      fprintf(f, "Filesystem features:     ");
++      for (i=0; i <3; i++,mask++) {
++              for (j=0,m=1; j < 32; j++, m<<=1) {
++                      if (*mask & m) {
++                              fprintf(f, " %s", e2p_feature2string(i, m));
++                              printed++;
++                      }
++              }
++      }
++      if (printed == 0)
++              fprintf(f, " (none)");
++      fprintf(f, "\n");
++#endif
++}
++
++static void print_mntopts(struct ext2_super_block * s, FILE *f)
++{
++#ifdef EXT2_DYNAMIC_REV
++      int     i, printed=0;
++      __u32   mask = s->s_default_mount_opts, m;
++
++      fprintf(f, "Default mount options:   ");
++      if (mask & EXT3_DEFM_JMODE) {
++              fprintf(f, " %s", e2p_mntopt2string(mask & EXT3_DEFM_JMODE));
++              printed++;
++      }
++      for (i=0,m=1; i < 32; i++, m<<=1) {
++              if (m & EXT3_DEFM_JMODE)
++                      continue;
++              if (mask & m) {
++                      fprintf(f, " %s", e2p_mntopt2string(m));
++                      printed++;
++              }
++      }
++      if (printed == 0)
++              fprintf(f, " (none)");
++      fprintf(f, "\n");
++#endif
++}
++
++
++#ifndef EXT2_INODE_SIZE
++#define EXT2_INODE_SIZE(s) sizeof(struct ext2_inode)
++#endif
++
++#ifndef EXT2_GOOD_OLD_REV
++#define EXT2_GOOD_OLD_REV 0
++#endif
++
++void list_super2(struct ext2_super_block * sb, FILE *f)
++{
++      int inode_blocks_per_group;
++      char buf[80], *str;
++      time_t  tm;
++
++      inode_blocks_per_group = (((sb->s_inodes_per_group *
++                                  EXT2_INODE_SIZE(sb)) +
++                                 EXT2_BLOCK_SIZE(sb) - 1) /
++                                EXT2_BLOCK_SIZE(sb));
++      if (sb->s_volume_name[0]) {
++              memset(buf, 0, sizeof(buf));
++              strncpy(buf, sb->s_volume_name, sizeof(sb->s_volume_name));
++      } else
++              strcpy(buf, "<none>");
++      fprintf(f, "Filesystem volume name:   %s\n", buf);
++      if (sb->s_last_mounted[0]) {
++              memset(buf, 0, sizeof(buf));
++              strncpy(buf, sb->s_last_mounted, sizeof(sb->s_last_mounted));
++      } else
++              strcpy(buf, "<not available>");
++      fprintf(f, "Last mounted on:          %s\n", buf);
++      fprintf(f, "Filesystem UUID:          %s\n", e2p_uuid2str(sb->s_uuid));
++      fprintf(f, "Filesystem magic number:  0x%04X\n", sb->s_magic);
++      fprintf(f, "Filesystem revision #:    %d", sb->s_rev_level);
++      if (sb->s_rev_level == EXT2_GOOD_OLD_REV) {
++              fprintf(f, " (original)\n");
++#ifdef EXT2_DYNAMIC_REV
++      } else if (sb->s_rev_level == EXT2_DYNAMIC_REV) {
++              fprintf(f, " (dynamic)\n");
++#endif
++      } else
++              fprintf(f, " (unknown)\n");
++      print_features(sb, f);
++      print_mntopts(sb, f);
++      fprintf(f, "Filesystem state:        ");
++      print_fs_state (f, sb->s_state);
++      fprintf(f, "\n");
++      fprintf(f, "Errors behavior:          ");
++      print_fs_errors(f, sb->s_errors);
++      fprintf(f, "\n");
++      str = e2p_os2string(sb->s_creator_os);
++      fprintf(f, "Filesystem OS type:       %s\n", str);
++      free(str);
++      fprintf(f, "Inode count:              %u\n", sb->s_inodes_count);
++      fprintf(f, "Block count:              %u\n", sb->s_blocks_count);
++      fprintf(f, "Reserved block count:     %u\n", sb->s_r_blocks_count);
++      fprintf(f, "Free blocks:              %u\n", sb->s_free_blocks_count);
++      fprintf(f, "Free inodes:              %u\n", sb->s_free_inodes_count);
++      fprintf(f, "First block:              %u\n", sb->s_first_data_block);
++      fprintf(f, "Block size:               %u\n", EXT2_BLOCK_SIZE(sb));
++      fprintf(f, "Fragment size:            %u\n", EXT2_FRAG_SIZE(sb));
++      if (sb->s_reserved_gdt_blocks)
++              fprintf(f, "Reserved GDT blocks:      %u\n", 
++                      sb->s_reserved_gdt_blocks);
++      fprintf(f, "Blocks per group:         %u\n", sb->s_blocks_per_group);
++      fprintf(f, "Fragments per group:      %u\n", sb->s_frags_per_group);
++      fprintf(f, "Inodes per group:         %u\n", sb->s_inodes_per_group);
++      fprintf(f, "Inode blocks per group:   %u\n", inode_blocks_per_group);
++      if (sb->s_first_meta_bg)
++              fprintf(f, "First meta block group:   %u\n",
++                      sb->s_first_meta_bg);
++      if (sb->s_mkfs_time) {
++              tm = sb->s_mkfs_time;
++              fprintf(f, "Filesystem created:       %s", ctime(&tm));
++      }
++      tm = sb->s_mtime;
++      fprintf(f, "Last mount time:          %s",
++              sb->s_mtime ? ctime(&tm) : "n/a\n");
++      tm = sb->s_wtime;
++      fprintf(f, "Last write time:          %s", ctime(&tm));
++      fprintf(f, "Mount count:              %u\n", sb->s_mnt_count);
++      fprintf(f, "Maximum mount count:      %d\n", sb->s_max_mnt_count);
++      tm = sb->s_lastcheck;
++      fprintf(f, "Last checked:             %s", ctime(&tm));
++      fprintf(f, "Check interval:           %u (%s)\n", sb->s_checkinterval,
++             interval_string(sb->s_checkinterval));
++      if (sb->s_checkinterval)
++      {
++              time_t next;
++
++              next = sb->s_lastcheck + sb->s_checkinterval;
++              fprintf(f, "Next check after:         %s", ctime(&next));
++      }
++      fprintf(f, "Reserved blocks uid:      ");
++      print_user(sb->s_def_resuid, f);
++      fprintf(f, "Reserved blocks gid:      ");
++      print_group(sb->s_def_resgid, f);
++      if (sb->s_rev_level >= EXT2_DYNAMIC_REV) {
++              fprintf(f, "First inode:              %d\n", sb->s_first_ino);
++              fprintf(f, "Inode size:           %d\n", sb->s_inode_size);
++      }
++      if (!e2p_is_null_uuid(sb->s_journal_uuid))
++              fprintf(f, "Journal UUID:             %s\n",
++                      e2p_uuid2str(sb->s_journal_uuid));
++      if (sb->s_journal_inum)
++              fprintf(f, "Journal inode:            %u\n",
++                      sb->s_journal_inum);
++      if (sb->s_journal_dev)
++              fprintf(f, "Journal device:               0x%04x\n",
++                      sb->s_journal_dev);
++      if (sb->s_last_orphan)
++              fprintf(f, "First orphan inode:       %u\n",
++                      sb->s_last_orphan);
++      if ((sb->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) ||
++          sb->s_def_hash_version)
++              fprintf(f, "Default directory hash:   %s\n",
++                      e2p_hash2string(sb->s_def_hash_version));
++      if (!e2p_is_null_uuid(sb->s_hash_seed))
++              fprintf(f, "Directory Hash Seed:      %s\n",
++                      e2p_uuid2str(sb->s_hash_seed));
++      if (sb->s_jnl_backup_type) {
++              fprintf(f, "Journal backup:           ");
++              switch (sb->s_jnl_backup_type) {
++              case 1:
++                      fprintf(f, "inode blocks\n");
++                      break;
++              default:
++                      fprintf(f, "type %u\n", sb->s_jnl_backup_type);
++              }
++      }
++}
++
++void list_super (struct ext2_super_block * s)
++{
++      list_super2(s, stdout);
++}
++
+diff -Nur busybox-1.00/e2fsprogs/e2p/mntopts.c busybox/e2fsprogs/e2p/mntopts.c
+--- busybox-1.00/e2fsprogs/e2p/mntopts.c       1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/e2p/mntopts.c    2005-06-04 08:20:15.000000000 +0200
+@@ -0,0 +1,136 @@
++/*
++ * mountopts.c --- convert between default mount options and strings
++ * 
++ * Copyright (C) 2002  Theodore Ts'o <tytso@mit.edu>
++ * 
++ * This file can be redistributed under the terms of the GNU Library General
++ * Public License
++ * 
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <ctype.h>
++#include <errno.h>
++
++#include "e2p.h"
++
++struct mntopt {
++      unsigned int    mask;
++      const char      *string;
++};
++
++static struct mntopt mntopt_list[] = {
++      { EXT2_DEFM_DEBUG,      "debug" },
++      { EXT2_DEFM_BSDGROUPS,  "bsdgroups" },
++      { EXT2_DEFM_XATTR_USER, "user_xattr" },
++      { EXT2_DEFM_ACL,        "acl" },
++      { EXT2_DEFM_UID16,      "uid16" },
++      { EXT3_DEFM_JMODE_DATA, "journal_data" },
++      { EXT3_DEFM_JMODE_ORDERED, "journal_data_ordered" },
++      { EXT3_DEFM_JMODE_WBACK, "journal_data_writeback" },
++      { 0, 0 },
++};
++
++const char *e2p_mntopt2string(unsigned int mask)
++{
++      struct mntopt  *f;
++      static char buf[20];
++      int     fnum;
++
++      for (f = mntopt_list; f->string; f++) {
++              if (mask == f->mask)
++                      return f->string;
++      }
++      for (fnum = 0; mask >>= 1; fnum++);
++      sprintf(buf, "MNTOPT_%d", fnum);
++      return buf;
++}
++
++int e2p_string2mntopt(char *string, unsigned int *mask)
++{
++      struct mntopt  *f;
++      char            *eptr;
++      int             num;
++
++      for (f = mntopt_list; f->string; f++) {
++              if (!strcasecmp(string, f->string)) {
++                      *mask = f->mask;
++                      return 0;
++              }
++      }
++      if (strncasecmp(string, "MNTOPT_", 8))
++              return 1;
++
++      if (string[8] == 0)
++              return 1;
++      num = strtol(string+8, &eptr, 10);
++      if (num > 32 || num < 0)
++              return 1;
++      if (*eptr)
++              return 1;
++      *mask = 1 << num;
++      return 0;
++}
++
++static char *skip_over_blanks(char *cp)
++{
++      while (*cp && isspace(*cp))
++              cp++;
++      return cp;
++}
++
++static char *skip_over_word(char *cp)
++{
++      while (*cp && !isspace(*cp) && *cp != ',')
++              cp++;
++      return cp;
++}
++
++/*
++ * Edit a mntopt set array as requested by the user.  The ok
++ * parameter, if non-zero, allows the application to limit what
++ * mntopts the user is allowed to set or clear using this function.
++ */
++int e2p_edit_mntopts(const char *str, __u32 *mntopts, __u32 ok)
++{
++      char    *cp, *buf, *next;
++      int     neg;
++      unsigned int    mask;
++
++      buf = malloc(strlen(str)+1);
++      if (!buf)
++              return 1;
++      strcpy(buf, str);
++      cp = buf;
++      while (cp && *cp) {
++              neg = 0;
++              cp = skip_over_blanks(cp);
++              next = skip_over_word(cp);
++              if (*next == 0)
++                      next = 0;
++              else
++                      *next = 0;
++              switch (*cp) {
++              case '-':
++              case '^':
++                      neg++;
++              case '+':
++                      cp++;
++                      break;
++              }
++              if (e2p_string2mntopt(cp, &mask))
++                      return 1;
++              if (ok && !(ok & mask))
++                      return 1;
++              if (mask & EXT3_DEFM_JMODE)
++                      *mntopts &= ~EXT3_DEFM_JMODE;
++              if (neg)
++                      *mntopts &= ~mask;
++              else
++                      *mntopts |= mask;
++              cp = next ? next+1 : 0;
++      }
++      return 0;
++}
+diff -Nur busybox-1.00/e2fsprogs/e2p/ostype.c busybox/e2fsprogs/e2p/ostype.c
+--- busybox-1.00/e2fsprogs/e2p/ostype.c        1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/e2p/ostype.c     2005-06-04 08:20:15.000000000 +0200
+@@ -0,0 +1,73 @@
++/*
++ * getostype.c          - Get the Filesystem OS type
++ *
++ * Copyright (C) 2004,2005  Theodore Ts'o <tytso@mit.edu>
++ *
++ * This file can be redistributed under the terms of the GNU Library General
++ * Public License
++ */
++
++#include "e2p.h"
++#include <string.h>
++
++const char *os_tab[] =
++      { "Linux", 
++        "Hurd", 
++        "Masix", 
++        "FreeBSD", 
++        "Lites",
++        0 };
++
++/*
++ * Convert an os_type to a string
++ */
++char *e2p_os2string(int os_type)
++{
++        const char    *os;
++      char            *ret;
++
++      if (os_type <= EXT2_OS_LITES)
++              os = os_tab[os_type];
++      else
++              os = "(unknown os)";
++
++        ret = malloc(strlen(os)+1);
++        strcpy(ret, os);
++        return ret;
++}
++
++/*
++ * Convert an os_type to a string
++ */
++int e2p_string2os(char *str)
++{
++      const char      **cpp;
++      int             i = 0;
++
++      for (cpp = os_tab; *cpp; cpp++, i++) {
++              if (!strcasecmp(str, *cpp))
++                      return i;
++      }
++      return -1;
++}
++
++#ifdef TEST_PROGRAM
++int main(int argc, char **argv)
++{
++      char    *s;
++      int     i, os;
++
++      for (i=0; i <= EXT2_OS_LITES; i++) {
++              s = e2p_os2string(i);
++              os = e2p_string2os(s);
++              printf("%d: %s (%d)\n", i, s, os);
++              if (i != os) {
++                      fprintf(stderr, "Failure!\n");
++                      exit(1);
++              }
++      }
++      exit(0);
++}
++#endif
++
++
+diff -Nur busybox-1.00/e2fsprogs/e2p/parse_num.c busybox/e2fsprogs/e2p/parse_num.c
+--- busybox-1.00/e2fsprogs/e2p/parse_num.c     1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/e2p/parse_num.c  2005-06-04 08:20:15.000000000 +0200
+@@ -0,0 +1,64 @@
++/*
++ * parse_num.c                - Parse the number of blocks 
++ *
++ * Copyright (C) 2004,2005  Theodore Ts'o <tytso@mit.edu>
++ * 
++ * This file can be redistributed under the terms of the GNU Library General
++ * Public License
++ */
++
++#include "e2p.h"
++
++#include <stdlib.h>
++
++unsigned long parse_num_blocks(const char *arg, int log_block_size)
++{
++      char *p;
++      unsigned long long num;
++
++      num = strtoull(arg, &p, 0);
++
++      if (p[0] && p[1]) 
++              return 0;
++
++      switch (*p) {           /* Using fall-through logic */
++      case 'T': case 't': 
++              num <<= 10;
++      case 'G': case 'g': 
++              num <<= 10;
++      case 'M': case 'm': 
++              num <<= 10;
++      case 'K': case 'k': 
++              num >>= log_block_size; 
++              break;
++      case 's': 
++              num >>= 1;
++              break;
++      case '\0':
++              break;
++      default: 
++              return 0;
++      }
++      return num;
++}
++
++#ifdef DEBUG
++#include <unistd.h>
++#include <stdio.h>
++
++main(int argc, char **argv)
++{
++      unsigned long num;
++      int log_block_size = 0;
++
++      if (argc != 2) {
++              fprintf(stderr, "Usage: %s arg\n", argv[0]);
++              exit(1);
++      }
++
++      num = parse_num_blocks(argv[1], log_block_size);
++
++      printf("Parsed number: %lu\n", num);
++      exit(0);
++}
++#endif
+diff -Nur busybox-1.00/e2fsprogs/e2p/pe.c busybox/e2fsprogs/e2p/pe.c
+--- busybox-1.00/e2fsprogs/e2p/pe.c    1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/e2p/pe.c 2005-06-04 08:20:15.000000000 +0200
+@@ -0,0 +1,37 @@
++/*
++ * pe.c                       - Print a second extended filesystem errors behavior
++ *
++ * Copyright (C) 1992, 1993, 1994  Remy Card <card@masi.ibp.fr>
++ *                                 Laboratoire MASI, Institut Blaise Pascal
++ *                                 Universite Pierre et Marie Curie (Paris VI)
++ *
++ * This file can be redistributed under the terms of the GNU Library General
++ * Public License
++ */
++
++/*
++ * History:
++ * 94/01/09   - Creation
++ */
++
++#include <stdio.h>
++
++#include "e2p.h"
++
++void print_fs_errors (FILE * f, unsigned short errors)
++{
++      switch (errors)
++      {
++              case EXT2_ERRORS_CONTINUE:
++                      fprintf (f, "Continue");
++                      break;
++              case EXT2_ERRORS_RO:
++                      fprintf (f, "Remount read-only");
++                      break;
++              case EXT2_ERRORS_PANIC:
++                      fprintf (f, "Panic");
++                      break;
++              default:
++                      fprintf (f, "Unknown (continue)");
++      }
++}
+diff -Nur busybox-1.00/e2fsprogs/e2p/pf.c busybox/e2fsprogs/e2p/pf.c
+--- busybox-1.00/e2fsprogs/e2p/pf.c    1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/e2p/pf.c 2005-06-04 08:20:15.000000000 +0200
+@@ -0,0 +1,74 @@
++/*
++ * pf.c                       - Print file attributes on an ext2 file system
++ *
++ * Copyright (C) 1993, 1994  Remy Card <card@masi.ibp.fr>
++ *                           Laboratoire MASI, Institut Blaise Pascal
++ *                           Universite Pierre et Marie Curie (Paris VI)
++ *
++ * This file can be redistributed under the terms of the GNU Library General
++ * Public License
++ */
++
++/*
++ * History:
++ * 93/10/30   - Creation
++ */
++
++#include <stdio.h>
++
++#include "e2p.h"
++
++struct flags_name {
++      unsigned long   flag;
++      const char      *short_name;
++      const char      *long_name;
++};
++
++static struct flags_name flags_array[] = {
++      { EXT2_SECRM_FL, "s", "Secure_Deletion" },
++      { EXT2_UNRM_FL, "u" , "Undelete" },
++      { EXT2_SYNC_FL, "S", "Synchronous_Updates" },
++      { EXT2_DIRSYNC_FL, "D", "Synchronous_Directory_Updates" },
++      { EXT2_IMMUTABLE_FL, "i", "Immutable" },
++      { EXT2_APPEND_FL, "a", "Append_Only" },
++      { EXT2_NODUMP_FL, "d", "No_Dump" },
++      { EXT2_NOATIME_FL, "A", "No_Atime" },
++      { EXT2_COMPR_FL, "c", "Compression_Requested" },
++#ifdef ENABLE_COMPRESSION
++      { EXT2_COMPRBLK_FL, "B", "Compressed_File" },
++      { EXT2_DIRTY_FL, "Z", "Compressed_Dirty_File" },
++      { EXT2_NOCOMPR_FL, "X", "Compression_Raw_Access" },
++      { EXT2_ECOMPR_FL, "E", "Compression_Error" },
++#endif
++      { EXT3_JOURNAL_DATA_FL, "j", "Journaled_Data" },
++      { EXT2_INDEX_FL, "I", "Indexed_direcctory" }, 
++      { EXT2_NOTAIL_FL, "t", "No_Tailmerging" },
++      { EXT2_TOPDIR_FL, "T", "Top_of_Directory_Hierarchies" },
++      { 0, NULL, NULL }
++};
++
++void print_flags (FILE * f, unsigned long flags, unsigned options)
++{
++      int long_opt = (options & PFOPT_LONG);
++      struct flags_name *fp;
++      int     first = 1;
++
++      for (fp = flags_array; fp->flag != 0; fp++) {
++              if (flags & fp->flag) {
++                      if (long_opt) {
++                              if (first)
++                                      first = 0;
++                              else
++                                      fputs(", ", f);
++                              fputs(fp->long_name, f);
++                      } else
++                              fputs(fp->short_name, f);
++              } else {
++                      if (!long_opt)
++                              fputs("-", f);
++              }
++      }
++      if (long_opt && first)
++              fputs("---", f);
++}
++
+diff -Nur busybox-1.00/e2fsprogs/e2p/ps.c busybox/e2fsprogs/e2p/ps.c
+--- busybox-1.00/e2fsprogs/e2p/ps.c    1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/e2p/ps.c 2005-06-04 08:20:15.000000000 +0200
+@@ -0,0 +1,29 @@
++/*
++ * ps.c                       - Print filesystem state
++ *
++ * Copyright (C) 1993, 1994  Remy Card <card@masi.ibp.fr>
++ *                           Laboratoire MASI, Institut Blaise Pascal
++ *                           Universite Pierre et Marie Curie (Paris VI)
++ *
++ * This file can be redistributed under the terms of the GNU Library General
++ * Public License
++ */
++
++/*
++ * History:
++ * 93/12/22   - Creation
++ */
++
++#include <stdio.h>
++
++#include "e2p.h"
++
++void print_fs_state (FILE * f, unsigned short state)
++{
++      if (state & EXT2_VALID_FS)
++              fprintf (f, " clean");
++      else
++              fprintf (f, " not clean");
++      if (state & EXT2_ERROR_FS)
++              fprintf (f, " with errors");
++}
+diff -Nur busybox-1.00/e2fsprogs/e2p/uuid.c busybox/e2fsprogs/e2p/uuid.c
+--- busybox-1.00/e2fsprogs/e2p/uuid.c  1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/e2p/uuid.c       2005-06-04 08:20:15.000000000 +0200
+@@ -0,0 +1,79 @@
++/*
++ * uuid.c -- utility routines for manipulating UUID's.
++ */
++
++#include <stdio.h>
++#include <string.h>
++#include <ext2fs/ext2_types.h>
++
++#include "e2p.h"
++
++struct uuid {
++      __u32   time_low;
++      __u16   time_mid;
++      __u16   time_hi_and_version;
++      __u16   clock_seq;
++      __u8    node[6];
++};
++
++/* Returns 1 if the uuid is the NULL uuid */
++int e2p_is_null_uuid(void *uu)
++{
++      __u8    *cp;
++      int     i;
++
++      for (i=0, cp = uu; i < 16; i++)
++              if (*cp)
++                      return 0;
++      return 1;
++}
++
++static void e2p_unpack_uuid(void *in, struct uuid *uu)
++{
++      __u8    *ptr = in;
++      __u32   tmp;
++
++      tmp = *ptr++;
++      tmp = (tmp << 8) | *ptr++;
++      tmp = (tmp << 8) | *ptr++;
++      tmp = (tmp << 8) | *ptr++;
++      uu->time_low = tmp;
++
++      tmp = *ptr++;
++      tmp = (tmp << 8) | *ptr++;
++      uu->time_mid = tmp;
++      
++      tmp = *ptr++;
++      tmp = (tmp << 8) | *ptr++;
++      uu->time_hi_and_version = tmp;
++
++      tmp = *ptr++;
++      tmp = (tmp << 8) | *ptr++;
++      uu->clock_seq = tmp;
++
++      memcpy(uu->node, ptr, 6);
++}
++
++void e2p_uuid_to_str(void *uu, char *out)
++{
++      struct uuid uuid;
++
++      e2p_unpack_uuid(uu, &uuid);
++      sprintf(out,
++              "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
++              uuid.time_low, uuid.time_mid, uuid.time_hi_and_version,
++              uuid.clock_seq >> 8, uuid.clock_seq & 0xFF,
++              uuid.node[0], uuid.node[1], uuid.node[2],
++              uuid.node[3], uuid.node[4], uuid.node[5]);
++}
++
++const char *e2p_uuid2str(void *uu)
++{
++      static char buf[80];
++
++      if (e2p_is_null_uuid(uu))
++              return "<none>";
++      e2p_uuid_to_str(uu, buf);
++      return buf;
++}
++
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/alloc.c busybox/e2fsprogs/ext2fs/alloc.c
+--- busybox-1.00/e2fsprogs/ext2fs/alloc.c      1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/alloc.c   2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,173 @@
++/*
++ * alloc.c --- allocate new inodes, blocks for ext2fs
++ *
++ * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ * 
++ */
++
++#include <stdio.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <time.h>
++#include <string.h>
++#if HAVE_SYS_STAT_H
++#include <sys/stat.h>
++#endif
++#if HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++/*
++ * Right now, just search forward from the parent directory's block
++ * group to find the next free inode.
++ *
++ * Should have a special policy for directories.
++ */
++errcode_t ext2fs_new_inode(ext2_filsys fs, ext2_ino_t dir, 
++                         int mode EXT2FS_ATTR((unused)),
++                         ext2fs_inode_bitmap map, ext2_ino_t *ret)
++{
++      ext2_ino_t      dir_group = 0;
++      ext2_ino_t      i;
++      ext2_ino_t      start_inode;
++
++      EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
++      
++      if (!map)
++              map = fs->inode_map;
++      if (!map)
++              return EXT2_ET_NO_INODE_BITMAP;
++      
++      if (dir > 0) 
++              dir_group = (dir - 1) / EXT2_INODES_PER_GROUP(fs->super);
++
++      start_inode = (dir_group * EXT2_INODES_PER_GROUP(fs->super)) + 1;
++      if (start_inode < EXT2_FIRST_INODE(fs->super))
++              start_inode = EXT2_FIRST_INODE(fs->super);
++      i = start_inode;
++
++      do {
++              if (!ext2fs_fast_test_inode_bitmap(map, i))
++                      break;
++              i++;
++              if (i > fs->super->s_inodes_count)
++                      i = EXT2_FIRST_INODE(fs->super);
++      } while (i != start_inode);
++      
++      if (ext2fs_test_inode_bitmap(map, i))
++              return EXT2_ET_INODE_ALLOC_FAIL;
++      *ret = i;
++      return 0;
++}
++
++/*
++ * Stupid algorithm --- we now just search forward starting from the
++ * goal.  Should put in a smarter one someday....
++ */
++errcode_t ext2fs_new_block(ext2_filsys fs, blk_t goal,
++                         ext2fs_block_bitmap map, blk_t *ret)
++{
++      blk_t   i;
++
++      EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
++
++      if (!map)
++              map = fs->block_map;
++      if (!map)
++              return EXT2_ET_NO_BLOCK_BITMAP;
++      if (!goal || (goal >= fs->super->s_blocks_count))
++              goal = fs->super->s_first_data_block;
++      i = goal;
++      do {
++              if (!ext2fs_fast_test_block_bitmap(map, i)) {
++                      *ret = i;
++                      return 0;
++              }
++              i++;
++              if (i >= fs->super->s_blocks_count)
++                      i = fs->super->s_first_data_block;
++      } while (i != goal);
++      return EXT2_ET_BLOCK_ALLOC_FAIL;
++}
++
++/*
++ * This function zeros out the allocated block, and updates all of the
++ * appropriate filesystem records.
++ */
++errcode_t ext2fs_alloc_block(ext2_filsys fs, blk_t goal,
++                           char *block_buf, blk_t *ret)
++{
++      errcode_t       retval;
++      blk_t           block;
++      char            *buf = 0;
++
++      if (!block_buf) {
++              retval = ext2fs_get_mem(fs->blocksize, &buf);
++              if (retval)
++                      return retval;
++              block_buf = buf;
++      }
++      memset(block_buf, 0, fs->blocksize);
++
++      if (!fs->block_map) {
++              retval = ext2fs_read_block_bitmap(fs);
++              if (retval)
++                      goto fail;
++      }
++
++      retval = ext2fs_new_block(fs, goal, 0, &block);
++      if (retval)
++              goto fail;
++
++      retval = io_channel_write_blk(fs->io, block, 1, block_buf);
++      if (retval)
++              goto fail;
++      
++      ext2fs_block_alloc_stats(fs, block, +1);
++      *ret = block;
++      return 0;
++
++fail:
++      if (buf)
++              ext2fs_free_mem(&buf);
++      return retval;
++}
++
++errcode_t ext2fs_get_free_blocks(ext2_filsys fs, blk_t start, blk_t finish,
++                               int num, ext2fs_block_bitmap map, blk_t *ret)
++{
++      blk_t   b = start;
++
++      EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
++
++      if (!map)
++              map = fs->block_map;
++      if (!map)
++              return EXT2_ET_NO_BLOCK_BITMAP;
++      if (!b)
++              b = fs->super->s_first_data_block;
++      if (!finish)
++              finish = start;
++      if (!num)
++              num = 1;
++      do {
++              if (b+num-1 > fs->super->s_blocks_count)
++                      b = fs->super->s_first_data_block;
++              if (ext2fs_fast_test_block_bitmap_range(map, b, num)) {
++                      *ret = b;
++                      return 0;
++              }
++              b++;
++      } while (b != finish);
++      return EXT2_ET_BLOCK_ALLOC_FAIL;
++}
++
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/alloc_sb.c busybox/e2fsprogs/ext2fs/alloc_sb.c
+--- busybox-1.00/e2fsprogs/ext2fs/alloc_sb.c   1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/alloc_sb.c        2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,57 @@
++/*
++ * alloc_sb.c --- Allocate the superblock and block group descriptors for a 
++ * newly initialized filesystem.  Used by mke2fs when initializing a filesystem
++ *
++ * Copyright (C) 1994, 1995, 1996, 2003 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <fcntl.h>
++#include <time.h>
++#if HAVE_SYS_STAT_H
++#include <sys/stat.h>
++#endif
++#if HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++int ext2fs_reserve_super_and_bgd(ext2_filsys fs, 
++                               dgrp_t group,
++                               ext2fs_block_bitmap bmap)
++{
++      blk_t   super_blk, old_desc_blk, new_desc_blk;
++      int     j, old_desc_blocks, num_blocks;
++
++      num_blocks = ext2fs_super_and_bgd_loc(fs, group, &super_blk, 
++                                            &old_desc_blk, &new_desc_blk, 0);
++
++      if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
++              old_desc_blocks = fs->super->s_first_meta_bg;
++      else
++              old_desc_blocks = 
++                      fs->desc_blocks + fs->super->s_reserved_gdt_blocks;
++
++      if (super_blk || (group == 0))
++              ext2fs_mark_block_bitmap(bmap, super_blk);
++
++      if (old_desc_blk) {
++              for (j=0; j < old_desc_blocks; j++)
++                      ext2fs_mark_block_bitmap(bmap, old_desc_blk + j);
++      }
++      if (new_desc_blk)
++              ext2fs_mark_block_bitmap(bmap, new_desc_blk);
++
++      return num_blocks;
++}
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/alloc_stats.c busybox/e2fsprogs/ext2fs/alloc_stats.c
+--- busybox-1.00/e2fsprogs/ext2fs/alloc_stats.c        1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/alloc_stats.c     2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,52 @@
++/*
++ * alloc_stats.c --- Update allocation statistics for ext2fs
++ *
++ * Copyright (C) 2001 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ * 
++ */
++
++#include <stdio.h>
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++void ext2fs_inode_alloc_stats2(ext2_filsys fs, ext2_ino_t ino,
++                             int inuse, int isdir)
++{
++      int     group = ext2fs_group_of_ino(fs, ino);
++
++      if (inuse > 0)
++              ext2fs_mark_inode_bitmap(fs->inode_map, ino);
++      else
++              ext2fs_unmark_inode_bitmap(fs->inode_map, ino);
++      fs->group_desc[group].bg_free_inodes_count -= inuse;
++      if (isdir)
++              fs->group_desc[group].bg_used_dirs_count += inuse;
++      fs->super->s_free_inodes_count -= inuse;
++      ext2fs_mark_super_dirty(fs);
++      ext2fs_mark_ib_dirty(fs);
++}
++
++void ext2fs_inode_alloc_stats(ext2_filsys fs, ext2_ino_t ino, int inuse)
++{
++      ext2fs_inode_alloc_stats2(fs, ino, inuse, 0);
++}
++
++void ext2fs_block_alloc_stats(ext2_filsys fs, blk_t blk, int inuse)
++{
++      int     group = ext2fs_group_of_blk(fs, blk);
++
++      if (inuse > 0)
++              ext2fs_mark_block_bitmap(fs->block_map, blk);
++      else
++              ext2fs_unmark_block_bitmap(fs->block_map, blk);
++      fs->group_desc[group].bg_free_blocks_count -= inuse;
++      fs->super->s_free_blocks_count -= inuse;
++      ext2fs_mark_super_dirty(fs);
++      ext2fs_mark_bb_dirty(fs);
++}
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/alloc_tables.c busybox/e2fsprogs/ext2fs/alloc_tables.c
+--- busybox-1.00/e2fsprogs/ext2fs/alloc_tables.c       1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/alloc_tables.c    2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,117 @@
++/*
++ * alloc_tables.c --- Allocate tables for a newly initialized
++ * filesystem.  Used by mke2fs when initializing a filesystem
++ *
++ * Copyright (C) 1996 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <fcntl.h>
++#include <time.h>
++#if HAVE_SYS_STAT_H
++#include <sys/stat.h>
++#endif
++#if HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++errcode_t ext2fs_allocate_group_table(ext2_filsys fs, dgrp_t group,
++                                    ext2fs_block_bitmap bmap)
++{
++      errcode_t       retval;
++      blk_t           group_blk, start_blk, last_blk, new_blk, blk;
++      int             j;
++
++      group_blk = fs->super->s_first_data_block +
++              (group * fs->super->s_blocks_per_group);
++      
++      last_blk = group_blk + fs->super->s_blocks_per_group;
++      if (last_blk >= fs->super->s_blocks_count)
++              last_blk = fs->super->s_blocks_count - 1;
++
++      if (!bmap)
++              bmap = fs->block_map;
++      
++      /*
++       * Allocate the block and inode bitmaps, if necessary
++       */
++      if (fs->stride) {
++              start_blk = group_blk + fs->inode_blocks_per_group;
++              start_blk += ((fs->stride * group) %
++                            (last_blk - start_blk));
++              if (start_blk > last_blk)
++                      start_blk = group_blk;
++      } else
++              start_blk = group_blk;
++
++      if (!fs->group_desc[group].bg_block_bitmap) {
++              retval = ext2fs_get_free_blocks(fs, start_blk, last_blk,
++                                              1, bmap, &new_blk);
++              if (retval == EXT2_ET_BLOCK_ALLOC_FAIL) 
++                      retval = ext2fs_get_free_blocks(fs, group_blk,
++                                      last_blk, 1, bmap, &new_blk);
++              if (retval)
++                      return retval;
++              ext2fs_mark_block_bitmap(bmap, new_blk);
++              fs->group_desc[group].bg_block_bitmap = new_blk;
++      }
++
++      if (!fs->group_desc[group].bg_inode_bitmap) {
++              retval = ext2fs_get_free_blocks(fs, start_blk, last_blk,
++                                              1, bmap, &new_blk);
++              if (retval == EXT2_ET_BLOCK_ALLOC_FAIL) 
++                      retval = ext2fs_get_free_blocks(fs, group_blk,
++                                      last_blk, 1, bmap, &new_blk);
++              if (retval)
++                      return retval;
++              ext2fs_mark_block_bitmap(bmap, new_blk);
++              fs->group_desc[group].bg_inode_bitmap = new_blk;
++      }
++
++      /*
++       * Allocate the inode table
++       */
++      if (!fs->group_desc[group].bg_inode_table) {
++              retval = ext2fs_get_free_blocks(fs, group_blk, last_blk,
++                                              fs->inode_blocks_per_group,
++                                              bmap, &new_blk);
++              if (retval)
++                      return retval;
++              for (j=0, blk = new_blk;
++                   j < fs->inode_blocks_per_group;
++                   j++, blk++)
++                      ext2fs_mark_block_bitmap(bmap, blk);
++              fs->group_desc[group].bg_inode_table = new_blk;
++      }
++
++      
++      return 0;
++}
++
++      
++
++errcode_t ext2fs_allocate_tables(ext2_filsys fs)
++{
++      errcode_t       retval;
++      dgrp_t          i;
++
++      for (i = 0; i < fs->group_desc_count; i++) {
++              retval = ext2fs_allocate_group_table(fs, i, fs->block_map);
++              if (retval)
++                      return retval;
++      }
++      return 0;
++}
++
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/badblocks.c busybox/e2fsprogs/ext2fs/badblocks.c
+--- busybox-1.00/e2fsprogs/ext2fs/badblocks.c  1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/badblocks.c       2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,327 @@
++/*
++ * badblocks.c --- routines to manipulate the bad block structure
++ * 
++ * Copyright (C) 1994, 1995, 1996 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <fcntl.h>
++#include <time.h>
++#if HAVE_SYS_STAT_H
++#include <sys/stat.h>
++#endif
++#if HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++
++#include "ext2_fs.h"
++#include "ext2fsP.h"
++
++/*
++ * Helper function for making a badblocks list
++ */
++static errcode_t make_u32_list(int size, int num, __u32 *list,
++                             ext2_u32_list *ret)
++{
++      ext2_u32_list   bb;
++      errcode_t       retval;
++      
++      retval = ext2fs_get_mem(sizeof(struct ext2_struct_u32_list), &bb);
++      if (retval)
++              return retval;
++      memset(bb, 0, sizeof(struct ext2_struct_u32_list));
++      bb->magic = EXT2_ET_MAGIC_BADBLOCKS_LIST;
++      bb->size = size ? size : 10;
++      bb->num = num;
++      retval = ext2fs_get_mem(bb->size * sizeof(blk_t), &bb->list);
++      if (!bb->list) {
++              ext2fs_free_mem(&bb);
++              return retval;
++      }
++      if (list)
++              memcpy(bb->list, list, bb->size * sizeof(blk_t));
++      else
++              memset(bb->list, 0, bb->size * sizeof(blk_t));
++      *ret = bb;
++      return 0;
++}
++      
++
++/*
++ * This procedure creates an empty u32 list.
++ */
++errcode_t ext2fs_u32_list_create(ext2_u32_list *ret, int size)
++{
++      return make_u32_list(size, 0, 0, ret);
++}
++
++/*
++ * This procedure creates an empty badblocks list.
++ */
++errcode_t ext2fs_badblocks_list_create(ext2_badblocks_list *ret, int size)
++{
++      return make_u32_list(size, 0, 0, (ext2_badblocks_list *) ret);
++}
++
++
++/*
++ * This procedure copies a badblocks list
++ */
++errcode_t ext2fs_u32_copy(ext2_u32_list src, ext2_u32_list *dest)
++{
++      errcode_t       retval;
++      
++      retval = make_u32_list(src->size, src->num, src->list, dest);
++      if (retval)
++              return retval;
++      (*dest)->badblocks_flags = src->badblocks_flags;
++      return 0;
++}
++
++errcode_t ext2fs_badblocks_copy(ext2_badblocks_list src,
++                              ext2_badblocks_list *dest)
++{
++      return ext2fs_u32_copy((ext2_u32_list) src,
++                             (ext2_u32_list *) dest);
++}
++
++/*
++ * This procedure frees a badblocks list.
++ *
++ * (note: moved to closefs.c)
++ */
++
++
++/*
++ * This procedure adds a block to a badblocks list.
++ */
++errcode_t ext2fs_u32_list_add(ext2_u32_list bb, __u32 blk)
++{
++      errcode_t       retval;
++      int             i, j;
++      unsigned long   old_size;
++
++      EXT2_CHECK_MAGIC(bb, EXT2_ET_MAGIC_BADBLOCKS_LIST);
++
++      if (bb->num >= bb->size) {
++              old_size = bb->size * sizeof(__u32);
++              bb->size += 100;
++              retval = ext2fs_resize_mem(old_size, bb->size * sizeof(__u32),
++                                         &bb->list);
++              if (retval) {
++                      bb->size -= 100;
++                      return retval;
++              }
++      }
++
++      /*
++       * Add special case code for appending to the end of the list
++       */
++      i = bb->num-1;
++      if ((bb->num != 0) && (bb->list[i] == blk))
++              return 0;
++      if ((bb->num == 0) || (bb->list[i] < blk)) {
++              bb->list[bb->num++] = blk;
++              return 0;
++      }
++
++      j = bb->num;
++      for (i=0; i < bb->num; i++) {
++              if (bb->list[i] == blk)
++                      return 0;
++              if (bb->list[i] > blk) {
++                      j = i;
++                      break;
++              }
++      }
++      for (i=bb->num; i > j; i--)
++              bb->list[i] = bb->list[i-1];
++      bb->list[j] = blk;
++      bb->num++;
++      return 0;
++}
++
++errcode_t ext2fs_badblocks_list_add(ext2_badblocks_list bb, blk_t blk)
++{
++      return ext2fs_u32_list_add((ext2_u32_list) bb, (__u32) blk);
++}
++
++/*
++ * This procedure finds a particular block is on a badblocks
++ * list.
++ */
++int ext2fs_u32_list_find(ext2_u32_list bb, __u32 blk)
++{
++      int     low, high, mid;
++
++      if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST)
++              return -1;
++
++      if (bb->num == 0)
++              return -1;
++
++      low = 0;
++      high = bb->num-1;
++      if (blk == bb->list[low])
++              return low;
++      if (blk == bb->list[high])
++              return high;
++
++      while (low < high) {
++              mid = (low+high)/2;
++              if (mid == low || mid == high)
++                      break;
++              if (blk == bb->list[mid])
++                      return mid;
++              if (blk < bb->list[mid])
++                      high = mid;
++              else
++                      low = mid;
++      }
++      return -1;
++}
++
++/*
++ * This procedure tests to see if a particular block is on a badblocks
++ * list.
++ */
++int ext2fs_u32_list_test(ext2_u32_list bb, __u32 blk)
++{
++      if (ext2fs_u32_list_find(bb, blk) < 0)
++              return 0;
++      else
++              return 1;
++}
++
++int ext2fs_badblocks_list_test(ext2_badblocks_list bb, blk_t blk)
++{
++      return ext2fs_u32_list_test((ext2_u32_list) bb, (__u32) blk);
++}
++
++
++/*
++ * Remove a block from the badblock list
++ */
++int ext2fs_u32_list_del(ext2_u32_list bb, __u32 blk)
++{
++      int     remloc, i;
++
++      if (bb->num == 0)
++              return -1;
++
++      remloc = ext2fs_u32_list_find(bb, blk);
++      if (remloc < 0)
++              return -1;
++
++      for (i = remloc ; i < bb->num-1; i++)
++              bb->list[i] = bb->list[i+1];
++      bb->num--;
++      return 0;
++}
++
++void ext2fs_badblocks_list_del(ext2_u32_list bb, __u32 blk)
++{
++      ext2fs_u32_list_del(bb, blk);
++}
++
++errcode_t ext2fs_u32_list_iterate_begin(ext2_u32_list bb,
++                                      ext2_u32_iterate *ret)
++{
++      ext2_u32_iterate iter;
++      errcode_t               retval;
++
++      EXT2_CHECK_MAGIC(bb, EXT2_ET_MAGIC_BADBLOCKS_LIST);
++
++      retval = ext2fs_get_mem(sizeof(struct ext2_struct_u32_iterate), &iter);
++      if (retval)
++              return retval;
++
++      iter->magic = EXT2_ET_MAGIC_BADBLOCKS_ITERATE;
++      iter->bb = bb;
++      iter->ptr = 0;
++      *ret = iter;
++      return 0;
++}
++
++errcode_t ext2fs_badblocks_list_iterate_begin(ext2_badblocks_list bb,
++                                            ext2_badblocks_iterate *ret)
++{
++      return ext2fs_u32_list_iterate_begin((ext2_u32_list) bb,
++                                            (ext2_u32_iterate *) ret);
++}
++
++
++int ext2fs_u32_list_iterate(ext2_u32_iterate iter, __u32 *blk)
++{
++      ext2_u32_list   bb;
++
++      if (iter->magic != EXT2_ET_MAGIC_BADBLOCKS_ITERATE)
++              return 0;
++
++      bb = iter->bb;
++
++      if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST)
++              return 0;
++      
++      if (iter->ptr < bb->num) {
++              *blk = bb->list[iter->ptr++];
++              return 1;
++      } 
++      *blk = 0;
++      return 0;
++}
++
++int ext2fs_badblocks_list_iterate(ext2_badblocks_iterate iter, blk_t *blk)
++{
++      return ext2fs_u32_list_iterate((ext2_u32_iterate) iter,
++                                     (__u32 *) blk);
++}
++
++
++void ext2fs_u32_list_iterate_end(ext2_u32_iterate iter)
++{
++      if (!iter || (iter->magic != EXT2_ET_MAGIC_BADBLOCKS_ITERATE))
++              return;
++
++      iter->bb = 0;
++      ext2fs_free_mem(&iter);
++}
++
++void ext2fs_badblocks_list_iterate_end(ext2_badblocks_iterate iter)
++{
++      ext2fs_u32_list_iterate_end((ext2_u32_iterate) iter);
++}
++
++
++int ext2fs_u32_list_equal(ext2_u32_list bb1, ext2_u32_list bb2)
++{
++      EXT2_CHECK_MAGIC(bb1, EXT2_ET_MAGIC_BADBLOCKS_LIST);
++      EXT2_CHECK_MAGIC(bb2, EXT2_ET_MAGIC_BADBLOCKS_LIST);
++
++      if (bb1->num != bb2->num)
++              return 0;
++
++      if (memcmp(bb1->list, bb2->list, bb1->num * sizeof(blk_t)) != 0)
++              return 0;
++      return 1;
++}
++
++int ext2fs_badblocks_equal(ext2_badblocks_list bb1, ext2_badblocks_list bb2)
++{
++      return ext2fs_u32_list_equal((ext2_u32_list) bb1,
++                                   (ext2_u32_list) bb2);
++}
++
++int ext2fs_u32_list_count(ext2_u32_list bb)
++{
++      return bb->num;
++}
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/bb_compat.c busybox/e2fsprogs/ext2fs/bb_compat.c
+--- busybox-1.00/e2fsprogs/ext2fs/bb_compat.c  1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/bb_compat.c       2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,63 @@
++/*
++ * bb_compat.c --- compatibility badblocks routines
++ * 
++ * Copyright (C) 1997 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <fcntl.h>
++#include <time.h>
++#if HAVE_SYS_STAT_H
++#include <sys/stat.h>
++#endif
++#if HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++
++#include "ext2_fs.h"
++#include "ext2fsP.h"
++
++errcode_t badblocks_list_create(badblocks_list *ret, int size)
++{
++      return ext2fs_badblocks_list_create(ret, size);
++}
++
++void badblocks_list_free(badblocks_list bb)
++{
++      ext2fs_badblocks_list_free(bb);
++}
++
++errcode_t badblocks_list_add(badblocks_list bb, blk_t blk)
++{
++      return ext2fs_badblocks_list_add(bb, blk);
++}
++
++int badblocks_list_test(badblocks_list bb, blk_t blk)
++{
++      return ext2fs_badblocks_list_test(bb, blk);
++}
++
++errcode_t badblocks_list_iterate_begin(badblocks_list bb,
++                                     badblocks_iterate *ret)
++{
++      return ext2fs_badblocks_list_iterate_begin(bb, ret);
++}
++
++int badblocks_list_iterate(badblocks_iterate iter, blk_t *blk)
++{
++      return ext2fs_badblocks_list_iterate(iter, blk);
++}
++
++void badblocks_list_iterate_end(badblocks_iterate iter)
++{
++      ext2fs_badblocks_list_iterate_end(iter);
++}
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/bb_inode.c busybox/e2fsprogs/ext2fs/bb_inode.c
+--- busybox-1.00/e2fsprogs/ext2fs/bb_inode.c   1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/bb_inode.c        2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,267 @@
++/*
++ * bb_inode.c --- routines to update the bad block inode.
++ * 
++ * WARNING: This routine modifies a lot of state in the filesystem; if
++ * this routine returns an error, the bad block inode may be in an
++ * inconsistent state.
++ * 
++ * Copyright (C) 1994, 1995 Theodore Ts'o.
++ * 
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <fcntl.h>
++#include <time.h>
++#if HAVE_SYS_STAT_H
++#include <sys/stat.h>
++#endif
++#if HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++struct set_badblock_record {
++      ext2_badblocks_iterate  bb_iter;
++      int             bad_block_count;
++      blk_t           *ind_blocks;
++      int             max_ind_blocks;
++      int             ind_blocks_size;
++      int             ind_blocks_ptr;
++      char            *block_buf;
++      errcode_t       err;
++};
++
++static int set_bad_block_proc(ext2_filsys fs, blk_t *block_nr,
++                            e2_blkcnt_t blockcnt,
++                            blk_t ref_block, int ref_offset,
++                            void *priv_data);
++static int clear_bad_block_proc(ext2_filsys fs, blk_t *block_nr,
++                              e2_blkcnt_t blockcnt,
++                              blk_t ref_block, int ref_offset,
++                              void *priv_data);
++      
++/*
++ * Given a bad blocks bitmap, update the bad blocks inode to reflect
++ * the map.
++ */
++errcode_t ext2fs_update_bb_inode(ext2_filsys fs, ext2_badblocks_list bb_list)
++{
++      errcode_t                       retval;
++      struct set_badblock_record      rec;
++      struct ext2_inode               inode;
++      
++      EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
++
++      if (!fs->block_map)
++              return EXT2_ET_NO_BLOCK_BITMAP;
++      
++      rec.bad_block_count = 0;
++      rec.ind_blocks_size = rec.ind_blocks_ptr = 0;
++      rec.max_ind_blocks = 10;
++      retval = ext2fs_get_mem(rec.max_ind_blocks * sizeof(blk_t),
++                              &rec.ind_blocks);
++      if (retval)
++              return retval;
++      memset(rec.ind_blocks, 0, rec.max_ind_blocks * sizeof(blk_t));
++      retval = ext2fs_get_mem(fs->blocksize, &rec.block_buf);
++      if (retval)
++              goto cleanup;
++      memset(rec.block_buf, 0, fs->blocksize);
++      rec.err = 0;
++      
++      /*
++       * First clear the old bad blocks (while saving the indirect blocks) 
++       */
++      retval = ext2fs_block_iterate2(fs, EXT2_BAD_INO,
++                                     BLOCK_FLAG_DEPTH_TRAVERSE, 0,
++                                     clear_bad_block_proc, &rec);
++      if (retval)
++              goto cleanup;
++      if (rec.err) {
++              retval = rec.err;
++              goto cleanup;
++      }
++      
++      /*
++       * Now set the bad blocks!
++       *
++       * First, mark the bad blocks as used.  This prevents a bad
++       * block from being used as an indirecto block for the bad
++       * block inode (!).
++       */
++      if (bb_list) {
++              retval = ext2fs_badblocks_list_iterate_begin(bb_list,
++                                                           &rec.bb_iter);
++              if (retval)
++                      goto cleanup;
++              retval = ext2fs_block_iterate2(fs, EXT2_BAD_INO,
++                                             BLOCK_FLAG_APPEND, 0,
++                                             set_bad_block_proc, &rec);
++              ext2fs_badblocks_list_iterate_end(rec.bb_iter);
++              if (retval) 
++                      goto cleanup;
++              if (rec.err) {
++                      retval = rec.err;
++                      goto cleanup;
++              }
++      }
++      
++      /*
++       * Update the bad block inode's mod time and block count
++       * field.  
++       */
++      retval = ext2fs_read_inode(fs, EXT2_BAD_INO, &inode);
++      if (retval)
++              goto cleanup;
++      
++      inode.i_atime = inode.i_mtime = time(0);
++      if (!inode.i_ctime)
++              inode.i_ctime = time(0);
++      inode.i_blocks = rec.bad_block_count * (fs->blocksize / 512);
++      inode.i_size = rec.bad_block_count * fs->blocksize;
++
++      retval = ext2fs_write_inode(fs, EXT2_BAD_INO, &inode);
++      if (retval)
++              goto cleanup;
++      
++cleanup:
++      ext2fs_free_mem(&rec.ind_blocks);
++      ext2fs_free_mem(&rec.block_buf);
++      return retval;
++}
++
++/*
++ * Helper function for update_bb_inode()
++ *
++ * Clear the bad blocks in the bad block inode, while saving the
++ * indirect blocks.
++ */
++#ifdef __TURBOC__
++ #pragma argsused
++#endif
++static int clear_bad_block_proc(ext2_filsys fs, blk_t *block_nr,
++                              e2_blkcnt_t blockcnt,
++                              blk_t ref_block EXT2FS_ATTR((unused)),
++                              int ref_offset EXT2FS_ATTR((unused)),
++                              void *priv_data)
++{
++      struct set_badblock_record *rec = (struct set_badblock_record *)
++              priv_data;
++      errcode_t       retval;
++      unsigned long   old_size;
++
++      if (!*block_nr)
++              return 0;
++
++      /*
++       * If the block number is outrageous, clear it and ignore it.
++       */
++      if (*block_nr >= fs->super->s_blocks_count ||
++          *block_nr < fs->super->s_first_data_block) {
++              *block_nr = 0;
++              return BLOCK_CHANGED;
++      }
++
++      if (blockcnt < 0) {
++              if (rec->ind_blocks_size >= rec->max_ind_blocks) {
++                      old_size = rec->max_ind_blocks * sizeof(blk_t);
++                      rec->max_ind_blocks += 10;
++                      retval = ext2fs_resize_mem(old_size, 
++                                 rec->max_ind_blocks * sizeof(blk_t),
++                                 &rec->ind_blocks);
++                      if (retval) {
++                              rec->max_ind_blocks -= 10;
++                              rec->err = retval;
++                              return BLOCK_ABORT;
++                      }
++              }
++              rec->ind_blocks[rec->ind_blocks_size++] = *block_nr;
++      }
++
++      /*
++       * Mark the block as unused, and update accounting information
++       */
++      ext2fs_block_alloc_stats(fs, *block_nr, -1);
++      
++      *block_nr = 0;
++      return BLOCK_CHANGED;
++}
++
++      
++/*
++ * Helper function for update_bb_inode()
++ *
++ * Set the block list in the bad block inode, using the supplied bitmap.
++ */
++#ifdef __TURBOC__
++ #pragma argsused
++#endif
++static int set_bad_block_proc(ext2_filsys fs, blk_t *block_nr,
++                            e2_blkcnt_t blockcnt,
++                            blk_t ref_block EXT2FS_ATTR((unused)),
++                            int ref_offset EXT2FS_ATTR((unused)),
++                            void *priv_data)
++{
++      struct set_badblock_record *rec = (struct set_badblock_record *)
++              priv_data;
++      errcode_t       retval;
++      blk_t           blk;
++
++      if (blockcnt >= 0) {
++              /*
++               * Get the next bad block.
++               */
++              if (!ext2fs_badblocks_list_iterate(rec->bb_iter, &blk))
++                      return BLOCK_ABORT;
++              rec->bad_block_count++;
++      } else {
++              /*
++               * An indirect block; fetch a block from the
++               * previously used indirect block list.  The block
++               * most be not marked as used; if so, get another one.
++               * If we run out of reserved indirect blocks, allocate
++               * a new one.
++               */
++      retry:
++              if (rec->ind_blocks_ptr < rec->ind_blocks_size) {
++                      blk = rec->ind_blocks[rec->ind_blocks_ptr++];
++                      if (ext2fs_test_block_bitmap(fs->block_map, blk))
++                              goto retry;
++              } else {
++                      retval = ext2fs_new_block(fs, 0, 0, &blk);
++                      if (retval) {
++                              rec->err = retval;
++                              return BLOCK_ABORT;
++                      }
++              }
++              retval = io_channel_write_blk(fs->io, blk, 1, rec->block_buf);
++              if (retval) {
++                      rec->err = retval;
++                      return BLOCK_ABORT;
++              }
++      }
++      
++      /*
++       * Update block counts
++       */
++      ext2fs_block_alloc_stats(fs, blk, +1);
++      
++      *block_nr = blk;
++      return BLOCK_CHANGED;
++}
++
++
++
++
++
++
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/bitmaps.c busybox/e2fsprogs/ext2fs/bitmaps.c
+--- busybox-1.00/e2fsprogs/ext2fs/bitmaps.c    1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/bitmaps.c 2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,212 @@
++/*
++ * bitmaps.c --- routines to read, write, and manipulate the inode and
++ * block bitmaps.
++ *
++ * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <fcntl.h>
++#include <time.h>
++#if HAVE_SYS_STAT_H
++#include <sys/stat.h>
++#endif
++#if HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++static errcode_t make_bitmap(__u32 start, __u32 end, __u32 real_end,
++                           const char *descr, char *init_map,
++                           ext2fs_generic_bitmap *ret)
++{
++      ext2fs_generic_bitmap   bitmap;
++      errcode_t               retval;
++      size_t                  size;
++
++      retval = ext2fs_get_mem(sizeof(struct ext2fs_struct_generic_bitmap), 
++                              &bitmap);
++      if (retval)
++              return retval;
++
++      bitmap->magic = EXT2_ET_MAGIC_GENERIC_BITMAP;
++      bitmap->fs = NULL;
++      bitmap->start = start;
++      bitmap->end = end;
++      bitmap->real_end = real_end;
++      bitmap->base_error_code = EXT2_ET_BAD_GENERIC_MARK;
++      if (descr) {
++              retval = ext2fs_get_mem(strlen(descr)+1, &bitmap->description);
++              if (retval) {
++                      ext2fs_free_mem(&bitmap);
++                      return retval;
++              }
++              strcpy(bitmap->description, descr);
++      } else
++              bitmap->description = 0;
++
++      size = (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1);
++      retval = ext2fs_get_mem(size, &bitmap->bitmap);
++      if (retval) {
++              ext2fs_free_mem(&bitmap->description);
++              ext2fs_free_mem(&bitmap);
++              return retval;
++      }
++
++      if (init_map)
++              memcpy(bitmap->bitmap, init_map, size);
++      else
++              memset(bitmap->bitmap, 0, size);
++      *ret = bitmap;
++      return 0;
++}
++
++errcode_t ext2fs_allocate_generic_bitmap(__u32 start,
++                                       __u32 end,
++                                       __u32 real_end,
++                                       const char *descr,
++                                       ext2fs_generic_bitmap *ret)
++{
++      return make_bitmap(start, end, real_end, descr, 0, ret);
++}
++
++errcode_t ext2fs_copy_bitmap(ext2fs_generic_bitmap src,
++                           ext2fs_generic_bitmap *dest)
++{
++      errcode_t               retval;
++      ext2fs_generic_bitmap   new_map;
++
++      retval = make_bitmap(src->start, src->end, src->real_end,
++                           src->description, src->bitmap, &new_map);
++      if (retval)
++              return retval;
++      new_map->magic = src->magic;
++      new_map->fs = src->fs;
++      new_map->base_error_code = src->base_error_code;
++      *dest = new_map;
++      return 0;
++}
++
++void ext2fs_set_bitmap_padding(ext2fs_generic_bitmap map)
++{
++      __u32   i, j;
++
++      for (i=map->end+1, j = i - map->start; i <= map->real_end; i++, j++)
++              ext2fs_set_bit(j, map->bitmap);
++
++      return;
++}     
++
++errcode_t ext2fs_allocate_inode_bitmap(ext2_filsys fs,
++                                     const char *descr,
++                                     ext2fs_inode_bitmap *ret)
++{
++      ext2fs_inode_bitmap bitmap;
++      errcode_t       retval;
++      __u32           start, end, real_end;
++
++      EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
++
++      fs->write_bitmaps = ext2fs_write_bitmaps;
++
++      start = 1;
++      end = fs->super->s_inodes_count;
++      real_end = (EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count);
++
++      retval = ext2fs_allocate_generic_bitmap(start, end, real_end,
++                                              descr, &bitmap);
++      if (retval)
++              return retval;
++      
++      bitmap->magic = EXT2_ET_MAGIC_INODE_BITMAP;
++      bitmap->fs = fs;
++      bitmap->base_error_code = EXT2_ET_BAD_INODE_MARK;
++      
++      *ret = bitmap;
++      return 0;
++}
++
++errcode_t ext2fs_allocate_block_bitmap(ext2_filsys fs,
++                                     const char *descr,
++                                     ext2fs_block_bitmap *ret)
++{
++      ext2fs_block_bitmap bitmap;
++      errcode_t       retval;
++      __u32           start, end, real_end;
++
++      EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
++
++      fs->write_bitmaps = ext2fs_write_bitmaps;
++
++      start = fs->super->s_first_data_block;
++      end = fs->super->s_blocks_count-1;
++      real_end = (EXT2_BLOCKS_PER_GROUP(fs->super)  
++                  * fs->group_desc_count)-1 + start;
++      
++      retval = ext2fs_allocate_generic_bitmap(start, end, real_end,
++                                              descr, &bitmap);
++      if (retval)
++              return retval;
++
++      bitmap->magic = EXT2_ET_MAGIC_BLOCK_BITMAP;
++      bitmap->fs = fs;
++      bitmap->base_error_code = EXT2_ET_BAD_BLOCK_MARK;
++      
++      *ret = bitmap;
++      return 0;
++}
++
++errcode_t ext2fs_fudge_inode_bitmap_end(ext2fs_inode_bitmap bitmap,
++                                      ext2_ino_t end, ext2_ino_t *oend)
++{
++      EXT2_CHECK_MAGIC(bitmap, EXT2_ET_MAGIC_INODE_BITMAP);
++      
++      if (end > bitmap->real_end)
++              return EXT2_ET_FUDGE_INODE_BITMAP_END;
++      if (oend)
++              *oend = bitmap->end;
++      bitmap->end = end;
++      return 0;
++}
++
++errcode_t ext2fs_fudge_block_bitmap_end(ext2fs_block_bitmap bitmap,
++                                      blk_t end, blk_t *oend)
++{
++      EXT2_CHECK_MAGIC(bitmap, EXT2_ET_MAGIC_BLOCK_BITMAP);
++      
++      if (end > bitmap->real_end)
++              return EXT2_ET_FUDGE_BLOCK_BITMAP_END;
++      if (oend)
++              *oend = bitmap->end;
++      bitmap->end = end;
++      return 0;
++}
++
++void ext2fs_clear_inode_bitmap(ext2fs_inode_bitmap bitmap)
++{
++      if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_INODE_BITMAP))
++              return;
++
++      memset(bitmap->bitmap, 0,
++             (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1));
++}
++
++void ext2fs_clear_block_bitmap(ext2fs_block_bitmap bitmap)
++{
++      if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_BLOCK_BITMAP))
++              return;
++
++      memset(bitmap->bitmap, 0,
++             (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1));
++}
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/bitops.c busybox/e2fsprogs/ext2fs/bitops.c
+--- busybox-1.00/e2fsprogs/ext2fs/bitops.c     1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/bitops.c  2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,91 @@
++/*
++ * bitops.c --- Bitmap frobbing code.  See bitops.h for the inlined
++ *    routines.
++ * 
++ * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#if HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++#ifndef _EXT2_HAVE_ASM_BITOPS_
++
++/*
++ * For the benefit of those who are trying to port Linux to another
++ * architecture, here are some C-language equivalents.  You should
++ * recode these in the native assmebly language, if at all possible.
++ *
++ * C language equivalents written by Theodore Ts'o, 9/26/92.
++ * Modified by Pete A. Zaitcev 7/14/95 to be portable to big endian
++ * systems, as well as non-32 bit systems.
++ */
++
++int ext2fs_set_bit(int nr,void * addr)
++{
++      int             mask, retval;
++      unsigned char   *ADDR = (unsigned char *) addr;
++
++      ADDR += nr >> 3;
++      mask = 1 << (nr & 0x07);
++      retval = mask & *ADDR;
++      *ADDR |= mask;
++      return retval;
++}
++
++int ext2fs_clear_bit(int nr, void * addr)
++{
++      int             mask, retval;
++      unsigned char   *ADDR = (unsigned char *) addr;
++
++      ADDR += nr >> 3;
++      mask = 1 << (nr & 0x07);
++      retval = mask & *ADDR;
++      *ADDR &= ~mask;
++      return retval;
++}
++
++int ext2fs_test_bit(int nr, const void * addr)
++{
++      int                     mask;
++      const unsigned char     *ADDR = (const unsigned char *) addr;
++
++      ADDR += nr >> 3;
++      mask = 1 << (nr & 0x07);
++      return (mask & *ADDR);
++}
++
++#endif        /* !_EXT2_HAVE_ASM_BITOPS_ */
++
++void ext2fs_warn_bitmap(errcode_t errcode, unsigned long arg,
++                      const char *description)
++{
++#ifndef OMIT_COM_ERR
++      if (description)
++              com_err(0, errcode, "#%lu for %s", arg, description);
++      else
++              com_err(0, errcode, "#%lu", arg);
++#endif
++}
++
++void ext2fs_warn_bitmap2(ext2fs_generic_bitmap bitmap,
++                          int code, unsigned long arg)
++{
++#ifndef OMIT_COM_ERR
++      if (bitmap->description)
++              com_err(0, bitmap->base_error_code+code,
++                      "#%lu for %s", arg, bitmap->description);
++      else
++              com_err(0, bitmap->base_error_code + code, "#%lu", arg);
++#endif
++}
++
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/bitops.h busybox/e2fsprogs/ext2fs/bitops.h
+--- busybox-1.00/e2fsprogs/ext2fs/bitops.h     1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/bitops.h  2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,617 @@
++/*
++ * bitops.h --- Bitmap frobbing code.  The byte swapping routines are
++ *    also included here.
++ * 
++ * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ * 
++ * i386 bitops operations taken from <asm/bitops.h>, Copyright 1992,
++ * Linus Torvalds.
++ */
++
++
++extern int ext2fs_set_bit(int nr,void * addr);
++extern int ext2fs_clear_bit(int nr, void * addr);
++extern int ext2fs_test_bit(int nr, const void * addr);
++extern __u16 ext2fs_swab16(__u16 val);
++extern __u32 ext2fs_swab32(__u32 val);
++
++#ifdef WORDS_BIGENDIAN
++#define ext2fs_cpu_to_le32(x) ext2fs_swab32((x))
++#define ext2fs_le32_to_cpu(x) ext2fs_swab32((x))
++#define ext2fs_cpu_to_le16(x) ext2fs_swab16((x))
++#define ext2fs_le16_to_cpu(x) ext2fs_swab16((x))
++#define ext2fs_cpu_to_be32(x) ((__u32)(x))
++#define ext2fs_be32_to_cpu(x) ((__u32)(x))
++#define ext2fs_cpu_to_be16(x) ((__u16)(x))
++#define ext2fs_be16_to_cpu(x) ((__u16)(x))
++#else
++#define ext2fs_cpu_to_le32(x) ((__u32)(x))
++#define ext2fs_le32_to_cpu(x) ((__u32)(x))
++#define ext2fs_cpu_to_le16(x) ((__u16)(x))
++#define ext2fs_le16_to_cpu(x) ((__u16)(x))
++#define ext2fs_cpu_to_be32(x) ext2fs_swab32((x))
++#define ext2fs_be32_to_cpu(x) ext2fs_swab32((x))
++#define ext2fs_cpu_to_be16(x) ext2fs_swab16((x))
++#define ext2fs_be16_to_cpu(x) ext2fs_swab16((x))
++#endif
++
++/*
++ * EXT2FS bitmap manipulation routines.
++ */
++
++/* Support for sending warning messages from the inline subroutines */
++extern const char *ext2fs_block_string;
++extern const char *ext2fs_inode_string;
++extern const char *ext2fs_mark_string;
++extern const char *ext2fs_unmark_string;
++extern const char *ext2fs_test_string;
++extern void ext2fs_warn_bitmap(errcode_t errcode, unsigned long arg,
++                             const char *description);
++extern void ext2fs_warn_bitmap2(ext2fs_generic_bitmap bitmap,
++                              int code, unsigned long arg);
++
++extern int ext2fs_mark_block_bitmap(ext2fs_block_bitmap bitmap, blk_t block);
++extern int ext2fs_unmark_block_bitmap(ext2fs_block_bitmap bitmap,
++                                     blk_t block);
++extern int ext2fs_test_block_bitmap(ext2fs_block_bitmap bitmap, blk_t block);
++
++extern int ext2fs_mark_inode_bitmap(ext2fs_inode_bitmap bitmap, ext2_ino_t inode);
++extern int ext2fs_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap,
++                                     ext2_ino_t inode);
++extern int ext2fs_test_inode_bitmap(ext2fs_inode_bitmap bitmap, ext2_ino_t inode);
++
++extern void ext2fs_fast_mark_block_bitmap(ext2fs_block_bitmap bitmap,
++                                        blk_t block);
++extern void ext2fs_fast_unmark_block_bitmap(ext2fs_block_bitmap bitmap,
++                                          blk_t block);
++extern int ext2fs_fast_test_block_bitmap(ext2fs_block_bitmap bitmap,
++                                       blk_t block);
++
++extern void ext2fs_fast_mark_inode_bitmap(ext2fs_inode_bitmap bitmap,
++                                        ext2_ino_t inode);
++extern void ext2fs_fast_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap,
++                                          ext2_ino_t inode);
++extern int ext2fs_fast_test_inode_bitmap(ext2fs_inode_bitmap bitmap,
++                                       ext2_ino_t inode);
++extern blk_t ext2fs_get_block_bitmap_start(ext2fs_block_bitmap bitmap);
++extern ext2_ino_t ext2fs_get_inode_bitmap_start(ext2fs_inode_bitmap bitmap);
++extern blk_t ext2fs_get_block_bitmap_end(ext2fs_block_bitmap bitmap);
++extern ext2_ino_t ext2fs_get_inode_bitmap_end(ext2fs_inode_bitmap bitmap);
++
++extern void ext2fs_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
++                                         blk_t block, int num);
++extern void ext2fs_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
++                                           blk_t block, int num);
++extern int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
++                                        blk_t block, int num);
++extern void ext2fs_fast_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
++                                              blk_t block, int num);
++extern void ext2fs_fast_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
++                                                blk_t block, int num);
++extern int ext2fs_fast_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
++                                             blk_t block, int num);
++extern void ext2fs_set_bitmap_padding(ext2fs_generic_bitmap map);
++
++/* These two routines moved to gen_bitmap.c */
++extern int ext2fs_mark_generic_bitmap(ext2fs_generic_bitmap bitmap,
++                                       __u32 bitno);
++extern int ext2fs_unmark_generic_bitmap(ext2fs_generic_bitmap bitmap,
++                                         blk_t bitno);
++/*
++ * The inline routines themselves...
++ * 
++ * If NO_INLINE_FUNCS is defined, then we won't try to do inline
++ * functions at all; they will be included as normal functions in
++ * inline.c
++ */
++#ifdef NO_INLINE_FUNCS
++#if (defined(__GNUC__) && (defined(__i386__) || defined(__i486__) || \
++                         defined(__i586__) || defined(__mc68000__) || \
++                         defined(__sparc__)))
++      /* This prevents bitops.c from trying to include the C */
++      /* function version of these functions */
++#define _EXT2_HAVE_ASM_BITOPS_
++#endif
++#endif /* NO_INLINE_FUNCS */
++
++#if (defined(INCLUDE_INLINE_FUNCS) || !defined(NO_INLINE_FUNCS))
++#ifdef INCLUDE_INLINE_FUNCS
++#define _INLINE_ extern
++#else
++#ifdef __GNUC__
++#define _INLINE_ extern __inline__
++#else                         /* For Watcom C */
++#define _INLINE_ extern inline
++#endif
++#endif
++
++#if ((defined __GNUC__) && !defined(_EXT2_USE_C_VERSIONS_) && \
++     (defined(__i386__) || defined(__i486__) || defined(__i586__)))
++
++#define _EXT2_HAVE_ASM_BITOPS_
++#define _EXT2_HAVE_ASM_SWAB_
++#define _EXT2_HAVE_ASM_FINDBIT_
++
++/*
++ * These are done by inline assembly for speed reasons.....
++ *
++ * All bitoperations return 0 if the bit was cleared before the
++ * operation and != 0 if it was not.  Bit 0 is the LSB of addr; bit 32
++ * is the LSB of (addr+1).
++ */
++
++/*
++ * Some hacks to defeat gcc over-optimizations..
++ */
++struct __dummy_h { unsigned long a[100]; };
++#define EXT2FS_ADDR (*(struct __dummy_h *) addr)
++#define EXT2FS_CONST_ADDR (*(const struct __dummy_h *) addr)  
++
++_INLINE_ int ext2fs_set_bit(int nr, void * addr)
++{
++      int oldbit;
++
++      __asm__ __volatile__("btsl %2,%1\n\tsbbl %0,%0"
++              :"=r" (oldbit),"=m" (EXT2FS_ADDR)
++              :"r" (nr));
++      return oldbit;
++}
++
++_INLINE_ int ext2fs_clear_bit(int nr, void * addr)
++{
++      int oldbit;
++
++      __asm__ __volatile__("btrl %2,%1\n\tsbbl %0,%0"
++              :"=r" (oldbit),"=m" (EXT2FS_ADDR)
++              :"r" (nr));
++      return oldbit;
++}
++
++_INLINE_ int ext2fs_test_bit(int nr, const void * addr)
++{
++      int oldbit;
++
++      __asm__ __volatile__("btl %2,%1\n\tsbbl %0,%0"
++              :"=r" (oldbit)
++              :"m" (EXT2FS_CONST_ADDR),"r" (nr));
++      return oldbit;
++}
++
++#if 0
++_INLINE_ int ext2fs_find_first_bit_set(void * addr, unsigned size)
++{
++      int d0, d1, d2;
++      int res;
++
++      if (!size)
++              return 0;
++      /* This looks at memory. Mark it volatile to tell gcc not to move it around */
++      __asm__ __volatile__(
++              "cld\n\t"                            
++              "xorl %%eax,%%eax\n\t"
++              "xorl %%edx,%%edx\n\t"
++              "repe; scasl\n\t"
++              "je 1f\n\t"
++              "movl -4(%%edi),%%eax\n\t"
++              "subl $4,%%edi\n\t"
++              "bsfl %%eax,%%edx\n"
++              "1:\tsubl %%esi,%%edi\n\t"
++              "shll $3,%%edi\n\t"
++              "addl %%edi,%%edx"
++              :"=d" (res), "=&c" (d0), "=&D" (d1), "=&a" (d2)
++              :"1" ((size + 31) >> 5), "2" (addr), "S" (addr));
++      return res;
++}
++
++_INLINE_ int ext2fs_find_next_bit_set (void * addr, int size, int offset)
++{
++      unsigned long * p = ((unsigned long *) addr) + (offset >> 5);
++      int set = 0, bit = offset & 31, res;
++      
++      if (bit) {
++              /*
++               * Look for zero in first byte
++               */
++              __asm__("bsfl %1,%0\n\t"
++                      "jne 1f\n\t"
++                      "movl $32, %0\n"
++                      "1:"
++                      : "=r" (set)
++                      : "r" (*p >> bit));
++              if (set < (32 - bit))
++                      return set + offset;
++              set = 32 - bit;
++              p++;
++      }
++      /*
++       * No bit found yet, search remaining full bytes for a bit
++       */
++      res = ext2fs_find_first_bit_set(p, size - 32 * (p - (unsigned long *) addr));
++      return (offset + set + res);
++}
++#endif
++
++#ifdef EXT2FS_ENABLE_SWAPFS
++_INLINE_ __u32 ext2fs_swab32(__u32 val)
++{
++#ifdef EXT2FS_REQUIRE_486
++      __asm__("bswap %0" : "=r" (val) : "0" (val));
++#else
++      __asm__("xchgb %b0,%h0\n\t"     /* swap lower bytes     */
++              "rorl $16,%0\n\t"       /* swap words           */
++              "xchgb %b0,%h0"         /* swap higher bytes    */
++              :"=q" (val)
++              : "0" (val));
++#endif
++      return val;
++}
++
++_INLINE_ __u16 ext2fs_swab16(__u16 val)
++{
++      __asm__("xchgb %b0,%h0"         /* swap bytes           */ \
++              : "=q" (val) \
++              :  "0" (val)); \
++              return val;
++}
++#endif
++
++#undef EXT2FS_ADDR
++
++#endif        /* i386 */
++
++#ifdef __mc68000__
++
++#define _EXT2_HAVE_ASM_BITOPS_
++
++_INLINE_ int ext2fs_set_bit(int nr,void * addr)
++{
++      char retval;
++
++      __asm__ __volatile__ ("bfset %2@{%1:#1}; sne %0"
++           : "=d" (retval) : "d" (nr^7), "a" (addr));
++
++      return retval;
++}
++
++_INLINE_ int ext2fs_clear_bit(int nr, void * addr)
++{
++      char retval;
++
++      __asm__ __volatile__ ("bfclr %2@{%1:#1}; sne %0"
++           : "=d" (retval) : "d" (nr^7), "a" (addr));
++
++      return retval;
++}
++
++_INLINE_ int ext2fs_test_bit(int nr, const void * addr)
++{
++      char retval;
++
++      __asm__ __volatile__ ("bftst %2@{%1:#1}; sne %0"
++           : "=d" (retval) : "d" (nr^7), "a" (addr));
++
++      return retval;
++}
++
++#endif /* __mc68000__ */
++
++
++#if !defined(_EXT2_HAVE_ASM_SWAB_) && defined(EXT2FS_ENABLE_SWAPFS)
++
++_INLINE_ __u16 ext2fs_swab16(__u16 val)
++{
++      return (val >> 8) | (val << 8);
++}
++
++_INLINE_ __u32 ext2fs_swab32(__u32 val)
++{
++      return ((val>>24) | ((val>>8)&0xFF00) |
++              ((val<<8)&0xFF0000) | (val<<24));
++}
++
++#endif /* !_EXT2_HAVE_ASM_SWAB */
++
++#if !defined(_EXT2_HAVE_ASM_FINDBIT_)
++_INLINE_ int ext2fs_find_first_bit_set(void * addr, unsigned size)
++{
++      char    *cp = (unsigned char *) addr;
++      int     res = 0, d0;
++
++      if (!size)
++              return 0;
++
++      while ((size > res) && (*cp == 0)) {
++              cp++;
++              res += 8;
++      }
++      d0 = ffs(*cp);
++      if (d0 == 0)
++              return size;
++      
++      return res + d0 - 1;
++}
++
++_INLINE_ int ext2fs_find_next_bit_set (void * addr, int size, int offset)
++{
++      unsigned char * p;
++      int set = 0, bit = offset & 7, res = 0, d0;
++      
++      res = offset >> 3;
++      p = ((unsigned char *) addr) + res;
++      
++      if (bit) {
++              set = ffs(*p & ~((1 << bit) - 1));
++              if (set)
++                      return (offset & ~7) + set - 1;
++              p++;
++              res += 8;
++      }
++      while ((size > res) && (*p == 0)) {
++              p++;
++              res += 8;
++      }
++      d0 = ffs(*p);
++      if (d0 == 0)
++              return size;
++
++      return (res + d0 - 1);
++}
++#endif        
++
++_INLINE_ int ext2fs_test_generic_bitmap(ext2fs_generic_bitmap bitmap,
++                                      blk_t bitno);
++
++_INLINE_ int ext2fs_test_generic_bitmap(ext2fs_generic_bitmap bitmap,
++                                      blk_t bitno)
++{
++      if ((bitno < bitmap->start) || (bitno > bitmap->end)) {
++              ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, bitno);
++              return 0;
++      }
++      return ext2fs_test_bit(bitno - bitmap->start, bitmap->bitmap);
++}
++
++_INLINE_ int ext2fs_mark_block_bitmap(ext2fs_block_bitmap bitmap,
++                                     blk_t block)
++{
++      return ext2fs_mark_generic_bitmap((ext2fs_generic_bitmap)
++                                     bitmap,
++                                        block);
++}
++
++_INLINE_ int ext2fs_unmark_block_bitmap(ext2fs_block_bitmap bitmap,
++                                       blk_t block)
++{
++      return ext2fs_unmark_generic_bitmap((ext2fs_generic_bitmap) bitmap, 
++                                          block);
++}
++
++_INLINE_ int ext2fs_test_block_bitmap(ext2fs_block_bitmap bitmap,
++                                     blk_t block)
++{
++      return ext2fs_test_generic_bitmap((ext2fs_generic_bitmap) bitmap, 
++                                        block);
++}
++
++_INLINE_ int ext2fs_mark_inode_bitmap(ext2fs_inode_bitmap bitmap,
++                                     ext2_ino_t inode)
++{
++      return ext2fs_mark_generic_bitmap((ext2fs_generic_bitmap) bitmap, 
++                                        inode);
++}
++
++_INLINE_ int ext2fs_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap,
++                                       ext2_ino_t inode)
++{
++      return ext2fs_unmark_generic_bitmap((ext2fs_generic_bitmap) bitmap, 
++                                   inode);
++}
++
++_INLINE_ int ext2fs_test_inode_bitmap(ext2fs_inode_bitmap bitmap,
++                                     ext2_ino_t inode)
++{
++      return ext2fs_test_generic_bitmap((ext2fs_generic_bitmap) bitmap, 
++                                        inode);
++}
++
++_INLINE_ void ext2fs_fast_mark_block_bitmap(ext2fs_block_bitmap bitmap,
++                                          blk_t block)
++{
++#ifdef EXT2FS_DEBUG_FAST_OPS
++      if ((block < bitmap->start) || (block > bitmap->end)) {
++              ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
++                                 bitmap->description);
++              return;
++      }
++#endif        
++      ext2fs_set_bit(block - bitmap->start, bitmap->bitmap);
++}
++
++_INLINE_ void ext2fs_fast_unmark_block_bitmap(ext2fs_block_bitmap bitmap,
++                                            blk_t block)
++{
++#ifdef EXT2FS_DEBUG_FAST_OPS
++      if ((block < bitmap->start) || (block > bitmap->end)) {
++              ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK,
++                                 block, bitmap->description);
++              return;
++      }
++#endif
++      ext2fs_clear_bit(block - bitmap->start, bitmap->bitmap);
++}
++
++_INLINE_ int ext2fs_fast_test_block_bitmap(ext2fs_block_bitmap bitmap,
++                                          blk_t block)
++{
++#ifdef EXT2FS_DEBUG_FAST_OPS
++      if ((block < bitmap->start) || (block > bitmap->end)) {
++              ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST,
++                                 block, bitmap->description);
++              return 0;
++      }
++#endif
++      return ext2fs_test_bit(block - bitmap->start, bitmap->bitmap);
++}
++
++_INLINE_ void ext2fs_fast_mark_inode_bitmap(ext2fs_inode_bitmap bitmap,
++                                          ext2_ino_t inode)
++{
++#ifdef EXT2FS_DEBUG_FAST_OPS
++      if ((inode < bitmap->start) || (inode > bitmap->end)) {
++              ext2fs_warn_bitmap(EXT2_ET_BAD_INODE_MARK,
++                                 inode, bitmap->description);
++              return;
++      }
++#endif
++      ext2fs_set_bit(inode - bitmap->start, bitmap->bitmap);
++}
++
++_INLINE_ void ext2fs_fast_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap,
++                                            ext2_ino_t inode)
++{
++#ifdef EXT2FS_DEBUG_FAST_OPS
++      if ((inode < bitmap->start) || (inode > bitmap->end)) {
++              ext2fs_warn_bitmap(EXT2_ET_BAD_INODE_UNMARK,
++                                 inode, bitmap->description);
++              return;
++      }
++#endif
++      ext2fs_clear_bit(inode - bitmap->start, bitmap->bitmap);
++}
++
++_INLINE_ int ext2fs_fast_test_inode_bitmap(ext2fs_inode_bitmap bitmap,
++                                         ext2_ino_t inode)
++{
++#ifdef EXT2FS_DEBUG_FAST_OPS
++      if ((inode < bitmap->start) || (inode > bitmap->end)) {
++              ext2fs_warn_bitmap(EXT2_ET_BAD_INODE_TEST,
++                                 inode, bitmap->description);
++              return 0;
++      }
++#endif
++      return ext2fs_test_bit(inode - bitmap->start, bitmap->bitmap);
++}
++
++_INLINE_ blk_t ext2fs_get_block_bitmap_start(ext2fs_block_bitmap bitmap)
++{
++      return bitmap->start;
++}
++
++_INLINE_ ext2_ino_t ext2fs_get_inode_bitmap_start(ext2fs_inode_bitmap bitmap)
++{
++      return bitmap->start;
++}
++
++_INLINE_ blk_t ext2fs_get_block_bitmap_end(ext2fs_block_bitmap bitmap)
++{
++      return bitmap->end;
++}
++
++_INLINE_ ext2_ino_t ext2fs_get_inode_bitmap_end(ext2fs_inode_bitmap bitmap)
++{
++      return bitmap->end;
++}
++
++_INLINE_ int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
++                                          blk_t block, int num)
++{
++      int     i;
++
++      if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
++              ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST,
++                                 block, bitmap->description);
++              return 0;
++      }
++      for (i=0; i < num; i++) {
++              if (ext2fs_fast_test_block_bitmap(bitmap, block+i))
++                      return 0;
++      }
++      return 1;
++}
++
++_INLINE_ int ext2fs_fast_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
++                                               blk_t block, int num)
++{
++      int     i;
++
++#ifdef EXT2FS_DEBUG_FAST_OPS
++      if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
++              ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST,
++                                 block, bitmap->description);
++              return 0;
++      }
++#endif
++      for (i=0; i < num; i++) {
++              if (ext2fs_fast_test_block_bitmap(bitmap, block+i))
++                      return 0;
++      }
++      return 1;
++}
++
++_INLINE_ void ext2fs_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
++                                           blk_t block, int num)
++{
++      int     i;
++      
++      if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
++              ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
++                                 bitmap->description);
++              return;
++      }
++      for (i=0; i < num; i++)
++              ext2fs_set_bit(block + i - bitmap->start, bitmap->bitmap);
++}
++
++_INLINE_ void ext2fs_fast_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
++                                                blk_t block, int num)
++{
++      int     i;
++      
++#ifdef EXT2FS_DEBUG_FAST_OPS
++      if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
++              ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
++                                 bitmap->description);
++              return;
++      }
++#endif        
++      for (i=0; i < num; i++)
++              ext2fs_set_bit(block + i - bitmap->start, bitmap->bitmap);
++}
++
++_INLINE_ void ext2fs_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
++                                             blk_t block, int num)
++{
++      int     i;
++      
++      if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
++              ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block,
++                                 bitmap->description);
++              return;
++      }
++      for (i=0; i < num; i++)
++              ext2fs_clear_bit(block + i - bitmap->start, bitmap->bitmap);
++}
++
++_INLINE_ void ext2fs_fast_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
++                                                  blk_t block, int num)
++{
++      int     i;
++      
++#ifdef EXT2FS_DEBUG_FAST_OPS
++      if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
++              ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block,
++                                 bitmap->description);
++              return;
++      }
++#endif        
++      for (i=0; i < num; i++)
++              ext2fs_clear_bit(block + i - bitmap->start, bitmap->bitmap);
++}
++#undef _INLINE_
++#endif
++
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/block.c busybox/e2fsprogs/ext2fs/block.c
+--- busybox-1.00/e2fsprogs/ext2fs/block.c      1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/block.c   2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,437 @@
++/*
++ * block.c --- iterate over all blocks in an inode
++ * 
++ * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++struct block_context {
++      ext2_filsys     fs;
++      int (*func)(ext2_filsys fs,
++                  blk_t       *blocknr,
++                  e2_blkcnt_t bcount,
++                  blk_t       ref_blk,
++                  int         ref_offset,
++                  void        *priv_data);
++      e2_blkcnt_t     bcount;
++      int             bsize;
++      int             flags;
++      errcode_t       errcode;
++      char    *ind_buf;
++      char    *dind_buf;
++      char    *tind_buf;
++      void    *priv_data;
++};
++
++static int block_iterate_ind(blk_t *ind_block, blk_t ref_block,
++                           int ref_offset, struct block_context *ctx)
++{
++      int     ret = 0, changed = 0;
++      int     i, flags, limit, offset;
++      blk_t   *block_nr;
++
++      limit = ctx->fs->blocksize >> 2;
++      if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
++          !(ctx->flags & BLOCK_FLAG_DATA_ONLY))
++              ret = (*ctx->func)(ctx->fs, ind_block,
++                                 BLOCK_COUNT_IND, ref_block,
++                                 ref_offset, ctx->priv_data);
++      if (!*ind_block || (ret & BLOCK_ABORT)) {
++              ctx->bcount += limit;
++              return ret;
++      }
++      if (*ind_block >= ctx->fs->super->s_blocks_count ||
++          *ind_block < ctx->fs->super->s_first_data_block) {
++              ctx->errcode = EXT2_ET_BAD_IND_BLOCK;
++              ret |= BLOCK_ERROR;
++              return ret;
++      }
++      ctx->errcode = ext2fs_read_ind_block(ctx->fs, *ind_block, 
++                                           ctx->ind_buf);
++      if (ctx->errcode) {
++              ret |= BLOCK_ERROR;
++              return ret;
++      }
++
++      block_nr = (blk_t *) ctx->ind_buf;
++      offset = 0;
++      if (ctx->flags & BLOCK_FLAG_APPEND) {
++              for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) {
++                      flags = (*ctx->func)(ctx->fs, block_nr, ctx->bcount,
++                                           *ind_block, offset, 
++                                           ctx->priv_data);
++                      changed |= flags;
++                      if (flags & BLOCK_ABORT) {
++                              ret |= BLOCK_ABORT;
++                              break;
++                      }
++                      offset += sizeof(blk_t);
++              }
++      } else {
++              for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) {
++                      if (*block_nr == 0)
++                              continue;
++                      flags = (*ctx->func)(ctx->fs, block_nr, ctx->bcount,
++                                           *ind_block, offset, 
++                                           ctx->priv_data);
++                      changed |= flags;
++                      if (flags & BLOCK_ABORT) {
++                              ret |= BLOCK_ABORT;
++                              break;
++                      }
++                      offset += sizeof(blk_t);
++              }
++      }
++      if (changed & BLOCK_CHANGED) {
++              ctx->errcode = ext2fs_write_ind_block(ctx->fs, *ind_block,
++                                                    ctx->ind_buf);
++              if (ctx->errcode)
++                      ret |= BLOCK_ERROR | BLOCK_ABORT;
++      }
++      if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
++          !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
++          !(ret & BLOCK_ABORT))
++              ret |= (*ctx->func)(ctx->fs, ind_block,
++                                  BLOCK_COUNT_IND, ref_block,
++                                  ref_offset, ctx->priv_data);
++      return ret;
++}
++      
++static int block_iterate_dind(blk_t *dind_block, blk_t ref_block,
++                            int ref_offset, struct block_context *ctx)
++{
++      int     ret = 0, changed = 0;
++      int     i, flags, limit, offset;
++      blk_t   *block_nr;
++
++      limit = ctx->fs->blocksize >> 2;
++      if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE |
++                          BLOCK_FLAG_DATA_ONLY)))
++              ret = (*ctx->func)(ctx->fs, dind_block,
++                                 BLOCK_COUNT_DIND, ref_block,
++                                 ref_offset, ctx->priv_data);
++      if (!*dind_block || (ret & BLOCK_ABORT)) {
++              ctx->bcount += limit*limit;
++              return ret;
++      }
++      if (*dind_block >= ctx->fs->super->s_blocks_count ||
++          *dind_block < ctx->fs->super->s_first_data_block) {
++              ctx->errcode = EXT2_ET_BAD_DIND_BLOCK;
++              ret |= BLOCK_ERROR;
++              return ret;
++      }
++      ctx->errcode = ext2fs_read_ind_block(ctx->fs, *dind_block, 
++                                           ctx->dind_buf);
++      if (ctx->errcode) {
++              ret |= BLOCK_ERROR;
++              return ret;
++      }
++
++      block_nr = (blk_t *) ctx->dind_buf;
++      offset = 0;
++      if (ctx->flags & BLOCK_FLAG_APPEND) {
++              for (i = 0; i < limit; i++, block_nr++) {
++                      flags = block_iterate_ind(block_nr,
++                                                *dind_block, offset,
++                                                ctx);
++                      changed |= flags;
++                      if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
++                              ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
++                              break;
++                      }
++                      offset += sizeof(blk_t);
++              }
++      } else {
++              for (i = 0; i < limit; i++, block_nr++) {
++                      if (*block_nr == 0) {
++                              ctx->bcount += limit;
++                              continue;
++                      }
++                      flags = block_iterate_ind(block_nr,
++                                                *dind_block, offset,
++                                                ctx);
++                      changed |= flags;
++                      if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
++                              ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
++                              break;
++                      }
++                      offset += sizeof(blk_t);
++              }
++      }
++      if (changed & BLOCK_CHANGED) {
++              ctx->errcode = ext2fs_write_ind_block(ctx->fs, *dind_block,
++                                                    ctx->dind_buf);
++              if (ctx->errcode)
++                      ret |= BLOCK_ERROR | BLOCK_ABORT;
++      }
++      if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
++          !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
++          !(ret & BLOCK_ABORT))
++              ret |= (*ctx->func)(ctx->fs, dind_block,
++                                  BLOCK_COUNT_DIND, ref_block,
++                                  ref_offset, ctx->priv_data);
++      return ret;
++}
++      
++static int block_iterate_tind(blk_t *tind_block, blk_t ref_block,
++                            int ref_offset, struct block_context *ctx)
++{
++      int     ret = 0, changed = 0;
++      int     i, flags, limit, offset;
++      blk_t   *block_nr;
++
++      limit = ctx->fs->blocksize >> 2;
++      if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE |
++                          BLOCK_FLAG_DATA_ONLY)))
++              ret = (*ctx->func)(ctx->fs, tind_block,
++                                 BLOCK_COUNT_TIND, ref_block,
++                                 ref_offset, ctx->priv_data);
++      if (!*tind_block || (ret & BLOCK_ABORT)) {
++              ctx->bcount += limit*limit*limit;
++              return ret;
++      }
++      if (*tind_block >= ctx->fs->super->s_blocks_count ||
++          *tind_block < ctx->fs->super->s_first_data_block) {
++              ctx->errcode = EXT2_ET_BAD_TIND_BLOCK;
++              ret |= BLOCK_ERROR;
++              return ret;
++      }
++      ctx->errcode = ext2fs_read_ind_block(ctx->fs, *tind_block, 
++                                           ctx->tind_buf);
++      if (ctx->errcode) {
++              ret |= BLOCK_ERROR;
++              return ret;
++      }
++
++      block_nr = (blk_t *) ctx->tind_buf;
++      offset = 0;
++      if (ctx->flags & BLOCK_FLAG_APPEND) {
++              for (i = 0; i < limit; i++, block_nr++) {
++                      flags = block_iterate_dind(block_nr,
++                                                 *tind_block,
++                                                 offset, ctx);
++                      changed |= flags;
++                      if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
++                              ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
++                              break;
++                      }
++                      offset += sizeof(blk_t);
++              }
++      } else {
++              for (i = 0; i < limit; i++, block_nr++) {
++                      if (*block_nr == 0) {
++                              ctx->bcount += limit*limit;
++                              continue;
++                      }
++                      flags = block_iterate_dind(block_nr,
++                                                 *tind_block,
++                                                 offset, ctx);
++                      changed |= flags;
++                      if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
++                              ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
++                              break;
++                      }
++                      offset += sizeof(blk_t);
++              }
++      }
++      if (changed & BLOCK_CHANGED) {
++              ctx->errcode = ext2fs_write_ind_block(ctx->fs, *tind_block,
++                                                    ctx->tind_buf);
++              if (ctx->errcode)
++                      ret |= BLOCK_ERROR | BLOCK_ABORT;
++      }
++      if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
++          !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
++          !(ret & BLOCK_ABORT))
++              ret |= (*ctx->func)(ctx->fs, tind_block,
++                                  BLOCK_COUNT_TIND, ref_block,
++                                  ref_offset, ctx->priv_data);
++      
++      return ret;
++}
++      
++errcode_t ext2fs_block_iterate2(ext2_filsys fs,
++                              ext2_ino_t ino,
++                              int     flags,
++                              char *block_buf,
++                              int (*func)(ext2_filsys fs,
++                                          blk_t       *blocknr,
++                                          e2_blkcnt_t blockcnt,
++                                          blk_t       ref_blk,
++                                          int         ref_offset,
++                                          void        *priv_data),
++                              void *priv_data)
++{
++      int     i;
++      int     got_inode = 0;
++      int     ret = 0;
++      blk_t   blocks[EXT2_N_BLOCKS];  /* directory data blocks */
++      struct ext2_inode inode;
++      errcode_t       retval;
++      struct block_context ctx;
++      int     limit;
++
++      EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
++
++      /*
++       * Check to see if we need to limit large files
++       */
++      if (flags & BLOCK_FLAG_NO_LARGE) {
++              ctx.errcode = ext2fs_read_inode(fs, ino, &inode);
++              if (ctx.errcode)
++                      return ctx.errcode;
++              got_inode = 1;
++              if (!LINUX_S_ISDIR(inode.i_mode) &&
++                  (inode.i_size_high != 0))
++                      return EXT2_ET_FILE_TOO_BIG;
++      }
++
++      retval = ext2fs_get_blocks(fs, ino, blocks);
++      if (retval)
++              return retval;
++
++      limit = fs->blocksize >> 2;
++
++      ctx.fs = fs;
++      ctx.func = func;
++      ctx.priv_data = priv_data;
++      ctx.flags = flags;
++      ctx.bcount = 0;
++      if (block_buf) {
++              ctx.ind_buf = block_buf;
++      } else {
++              retval = ext2fs_get_mem(fs->blocksize * 3, &ctx.ind_buf);
++              if (retval)
++                      return retval;
++      }
++      ctx.dind_buf = ctx.ind_buf + fs->blocksize;
++      ctx.tind_buf = ctx.dind_buf + fs->blocksize;
++
++      /*
++       * Iterate over the HURD translator block (if present)
++       */
++      if ((fs->super->s_creator_os == EXT2_OS_HURD) &&
++          !(flags & BLOCK_FLAG_DATA_ONLY)) {
++              ctx.errcode = ext2fs_read_inode(fs, ino, &inode);
++              if (ctx.errcode)
++                      goto abort_exit;
++              got_inode = 1;
++              if (inode.osd1.hurd1.h_i_translator) {
++                      ret |= (*ctx.func)(fs,
++                                         &inode.osd1.hurd1.h_i_translator,
++                                         BLOCK_COUNT_TRANSLATOR,
++                                         0, 0, priv_data);
++                      if (ret & BLOCK_ABORT)
++                              goto abort_exit;
++              }
++      }
++      
++      /*
++       * Iterate over normal data blocks
++       */
++      for (i = 0; i < EXT2_NDIR_BLOCKS ; i++, ctx.bcount++) {
++              if (blocks[i] || (flags & BLOCK_FLAG_APPEND)) {
++                      ret |= (*ctx.func)(fs, &blocks[i],
++                                          ctx.bcount, 0, i, priv_data);
++                      if (ret & BLOCK_ABORT)
++                              goto abort_exit;
++              }
++      }
++      if (*(blocks + EXT2_IND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
++              ret |= block_iterate_ind(blocks + EXT2_IND_BLOCK,
++                                       0, EXT2_IND_BLOCK, &ctx);
++              if (ret & BLOCK_ABORT)
++                      goto abort_exit;
++      } else
++              ctx.bcount += limit;
++      if (*(blocks + EXT2_DIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
++              ret |= block_iterate_dind(blocks + EXT2_DIND_BLOCK,
++                                        0, EXT2_DIND_BLOCK, &ctx);
++              if (ret & BLOCK_ABORT)
++                      goto abort_exit;
++      } else
++              ctx.bcount += limit * limit;
++      if (*(blocks + EXT2_TIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
++              ret |= block_iterate_tind(blocks + EXT2_TIND_BLOCK,
++                                        0, EXT2_TIND_BLOCK, &ctx);
++              if (ret & BLOCK_ABORT)
++                      goto abort_exit;
++      }
++
++abort_exit:
++      if (ret & BLOCK_CHANGED) {
++              if (!got_inode) {
++                      retval = ext2fs_read_inode(fs, ino, &inode);
++                      if (retval)
++                              return retval;
++              }
++              for (i=0; i < EXT2_N_BLOCKS; i++)
++                      inode.i_block[i] = blocks[i];
++              retval = ext2fs_write_inode(fs, ino, &inode);
++              if (retval)
++                      return retval;
++      }
++
++      if (!block_buf)
++              ext2fs_free_mem(&ctx.ind_buf);
++
++      return (ret & BLOCK_ERROR) ? ctx.errcode : 0;
++}
++
++/*
++ * Emulate the old ext2fs_block_iterate function!
++ */
++
++struct xlate {
++      int (*func)(ext2_filsys fs,
++                  blk_t       *blocknr,
++                  int         bcount,
++                  void        *priv_data);
++      void *real_private;
++};
++
++#ifdef __TURBOC__
++ #pragma argsused
++#endif
++static int xlate_func(ext2_filsys fs, blk_t *blocknr, e2_blkcnt_t blockcnt,
++                    blk_t ref_block EXT2FS_ATTR((unused)),
++                    int ref_offset EXT2FS_ATTR((unused)),
++                    void *priv_data)
++{
++      struct xlate *xl = (struct xlate *) priv_data;
++
++      return (*xl->func)(fs, blocknr, (int) blockcnt, xl->real_private);
++}
++
++errcode_t ext2fs_block_iterate(ext2_filsys fs,
++                             ext2_ino_t ino,
++                             int      flags,
++                             char *block_buf,
++                             int (*func)(ext2_filsys fs,
++                                         blk_t        *blocknr,
++                                         int  blockcnt,
++                                         void *priv_data),
++                             void *priv_data)
++{
++      struct xlate xl;
++      
++      xl.real_private = priv_data;
++      xl.func = func;
++
++      return ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_NO_LARGE | flags,
++                                   block_buf, xlate_func, &xl);
++}
++
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/bmap.c busybox/e2fsprogs/ext2fs/bmap.c
+--- busybox-1.00/e2fsprogs/ext2fs/bmap.c       1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/bmap.c    2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,270 @@
++/*
++ * bmap.c --- logical to physical block mapping
++ *
++ * Copyright (C) 1997 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++#if defined(__GNUC__) && !defined(NO_INLINE_FUNCS)
++#define _BMAP_INLINE_ __inline__
++#else
++#define _BMAP_INLINE_
++#endif
++
++extern errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino,
++                           struct ext2_inode *inode, 
++                           char *block_buf, int bmap_flags,
++                           blk_t block, blk_t *phys_blk);
++
++#define inode_bmap(inode, nr) ((inode)->i_block[(nr)])
++
++static _BMAP_INLINE_ errcode_t block_ind_bmap(ext2_filsys fs, int flags, 
++                                            blk_t ind, char *block_buf, 
++                                            int *blocks_alloc,
++                                            blk_t nr, blk_t *ret_blk)
++{
++      errcode_t       retval;
++      blk_t           b;
++
++      if (!ind) {
++              if (flags & BMAP_SET)
++                      return EXT2_ET_SET_BMAP_NO_IND;
++              *ret_blk = 0;
++              return 0;
++      }
++      retval = io_channel_read_blk(fs->io, ind, 1, block_buf);
++      if (retval)
++              return retval;
++
++      if (flags & BMAP_SET) {
++              b = *ret_blk;
++#ifdef EXT2FS_ENABLE_SWAPFS
++              if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
++                  (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
++                      b = ext2fs_swab32(b);
++#endif
++              ((blk_t *) block_buf)[nr] = b;
++              return io_channel_write_blk(fs->io, ind, 1, block_buf);
++      }
++
++      b = ((blk_t *) block_buf)[nr];
++
++#ifdef EXT2FS_ENABLE_SWAPFS
++      if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
++          (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
++              b = ext2fs_swab32(b);
++#endif
++
++      if (!b && (flags & BMAP_ALLOC)) {
++              b = nr ? ((blk_t *) block_buf)[nr-1] : 0;
++              retval = ext2fs_alloc_block(fs, b,
++                                          block_buf + fs->blocksize, &b);
++              if (retval)
++                      return retval;
++
++#ifdef EXT2FS_ENABLE_SWAPFS
++              if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
++                  (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
++                      ((blk_t *) block_buf)[nr] = ext2fs_swab32(b);
++              else
++#endif
++                      ((blk_t *) block_buf)[nr] = b;
++
++              retval = io_channel_write_blk(fs->io, ind, 1, block_buf);
++              if (retval)
++                      return retval;
++
++              (*blocks_alloc)++;
++      }
++
++      *ret_blk = b;
++      return 0;
++}
++
++static _BMAP_INLINE_ errcode_t block_dind_bmap(ext2_filsys fs, int flags,
++                                             blk_t dind, char *block_buf, 
++                                             int *blocks_alloc,
++                                             blk_t nr, blk_t *ret_blk)
++{
++      blk_t           b;
++      errcode_t       retval;
++      blk_t           addr_per_block;
++      
++      addr_per_block = (blk_t) fs->blocksize >> 2;
++
++      retval = block_ind_bmap(fs, flags & ~BMAP_SET, dind, block_buf, 
++                              blocks_alloc, nr / addr_per_block, &b);
++      if (retval)
++              return retval;
++      retval = block_ind_bmap(fs, flags, b, block_buf, blocks_alloc,
++                              nr % addr_per_block, ret_blk);
++      return retval;
++}
++
++static _BMAP_INLINE_ errcode_t block_tind_bmap(ext2_filsys fs, int flags,
++                                             blk_t tind, char *block_buf, 
++                                             int *blocks_alloc,
++                                             blk_t nr, blk_t *ret_blk)
++{
++      blk_t           b;
++      errcode_t       retval;
++      blk_t           addr_per_block;
++      
++      addr_per_block = (blk_t) fs->blocksize >> 2;
++
++      retval = block_dind_bmap(fs, flags & ~BMAP_SET, tind, block_buf, 
++                               blocks_alloc, nr / addr_per_block, &b);
++      if (retval)
++              return retval;
++      retval = block_ind_bmap(fs, flags, b, block_buf, blocks_alloc,
++                              nr % addr_per_block, ret_blk);
++      return retval;
++}
++
++errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode,
++                    char *block_buf, int bmap_flags, blk_t block,
++                    blk_t *phys_blk)
++{
++      struct ext2_inode inode_buf;
++      blk_t addr_per_block;
++      blk_t   b;
++      char    *buf = 0;
++      errcode_t       retval = 0;
++      int             blocks_alloc = 0, inode_dirty = 0;
++
++      if (!(bmap_flags & BMAP_SET))
++              *phys_blk = 0;
++
++      /* Read inode structure if necessary */
++      if (!inode) {
++              retval = ext2fs_read_inode(fs, ino, &inode_buf);
++              if (retval)
++                      return retval;
++              inode = &inode_buf;
++      }
++      addr_per_block = (blk_t) fs->blocksize >> 2;
++
++      if (!block_buf) {
++              retval = ext2fs_get_mem(fs->blocksize * 2, &buf);
++              if (retval)
++                      return retval;
++              block_buf = buf;
++      }
++
++      if (block < EXT2_NDIR_BLOCKS) {
++              if (bmap_flags & BMAP_SET) {
++                      b = *phys_blk;
++#ifdef EXT2FS_ENABLE_SWAPFS
++                      if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
++                          (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
++                              b = ext2fs_swab32(b);
++#endif
++                      inode_bmap(inode, block) = b;
++                      inode_dirty++;
++                      goto done;
++              }
++
++              *phys_blk = inode_bmap(inode, block);
++              b = block ? inode_bmap(inode, block-1) : 0;
++              
++              if ((*phys_blk == 0) && (bmap_flags & BMAP_ALLOC)) {
++                      retval = ext2fs_alloc_block(fs, b, block_buf, &b);
++                      if (retval)
++                              goto done;
++                      inode_bmap(inode, block) = b;
++                      blocks_alloc++;
++                      *phys_blk = b;
++              }
++              goto done;
++      }
++      
++      /* Indirect block */
++      block -= EXT2_NDIR_BLOCKS;
++      if (block < addr_per_block) {
++              b = inode_bmap(inode, EXT2_IND_BLOCK);
++              if (!b) {
++                      if (!(bmap_flags & BMAP_ALLOC)) {
++                              if (bmap_flags & BMAP_SET)
++                                      retval = EXT2_ET_SET_BMAP_NO_IND;
++                              goto done;
++                      }
++
++                      b = inode_bmap(inode, EXT2_IND_BLOCK-1);
++                      retval = ext2fs_alloc_block(fs, b, block_buf, &b);
++                      if (retval)
++                              goto done;
++                      inode_bmap(inode, EXT2_IND_BLOCK) = b;
++                      blocks_alloc++;
++              }
++              retval = block_ind_bmap(fs, bmap_flags, b, block_buf, 
++                                      &blocks_alloc, block, phys_blk);
++              goto done;
++      }
++      
++      /* Doubly indirect block  */
++      block -= addr_per_block;
++      if (block < addr_per_block * addr_per_block) {
++              b = inode_bmap(inode, EXT2_DIND_BLOCK);
++              if (!b) {
++                      if (!(bmap_flags & BMAP_ALLOC)) {
++                              if (bmap_flags & BMAP_SET)
++                                      retval = EXT2_ET_SET_BMAP_NO_IND;
++                              goto done;
++                      }
++
++                      b = inode_bmap(inode, EXT2_IND_BLOCK);
++                      retval = ext2fs_alloc_block(fs, b, block_buf, &b);
++                      if (retval)
++                              goto done;
++                      inode_bmap(inode, EXT2_DIND_BLOCK) = b;
++                      blocks_alloc++;
++              }
++              retval = block_dind_bmap(fs, bmap_flags, b, block_buf, 
++                                       &blocks_alloc, block, phys_blk);
++              goto done;
++      }
++
++      /* Triply indirect block */
++      block -= addr_per_block * addr_per_block;
++      b = inode_bmap(inode, EXT2_TIND_BLOCK);
++      if (!b) {
++              if (!(bmap_flags & BMAP_ALLOC)) {
++                      if (bmap_flags & BMAP_SET)
++                              retval = EXT2_ET_SET_BMAP_NO_IND;
++                      goto done;
++              }
++
++              b = inode_bmap(inode, EXT2_DIND_BLOCK);
++              retval = ext2fs_alloc_block(fs, b, block_buf, &b);
++              if (retval)
++                      goto done;
++              inode_bmap(inode, EXT2_TIND_BLOCK) = b;
++              blocks_alloc++;
++      }
++      retval = block_tind_bmap(fs, bmap_flags, b, block_buf, 
++                               &blocks_alloc, block, phys_blk);
++done:
++      if (buf)
++              ext2fs_free_mem(&buf);
++      if ((retval == 0) && (blocks_alloc || inode_dirty)) {
++              inode->i_blocks += (blocks_alloc * fs->blocksize) / 512;
++              retval = ext2fs_write_inode(fs, ino, inode);
++      }
++      return retval;
++}
++
++
++
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/bmove.c busybox/e2fsprogs/ext2fs/bmove.c
+--- busybox-1.00/e2fsprogs/ext2fs/bmove.c      1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/bmove.c   2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,160 @@
++/*
++ * bmove.c --- Move blocks around to make way for a particular
++ *    filesystem structure.
++ *
++ * Copyright (C) 1997 Theodore Ts'o.  This file may be redistributed
++ * under the terms of the GNU Public License.
++ */
++
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#if HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++#if HAVE_SYS_TIME_H
++#include <sys/time.h>
++#endif
++
++#include "ext2_fs.h"
++#include "ext2fsP.h"
++
++struct process_block_struct {
++      ext2_ino_t              ino;
++      struct ext2_inode *     inode;
++      ext2fs_block_bitmap     reserve;
++      ext2fs_block_bitmap     alloc_map;
++      errcode_t               error;
++      char                    *buf;
++      int                     add_dir;
++      int                     flags;
++};
++
++static int process_block(ext2_filsys fs, blk_t        *block_nr,
++                       e2_blkcnt_t blockcnt, blk_t ref_block,
++                       int ref_offset, void *priv_data)
++{
++      struct process_block_struct *pb;
++      errcode_t       retval;
++      int             ret;
++      blk_t           block, orig;
++
++      pb = (struct process_block_struct *) priv_data;
++      block = orig = *block_nr;
++      ret = 0;
++      
++      /*
++       * Let's see if this is one which we need to relocate
++       */
++      if (ext2fs_test_block_bitmap(pb->reserve, block)) {
++              do {
++                      if (++block >= fs->super->s_blocks_count)
++                              block = fs->super->s_first_data_block;
++                      if (block == orig) {
++                              pb->error = EXT2_ET_BLOCK_ALLOC_FAIL;
++                              return BLOCK_ABORT;
++                      }
++              } while (ext2fs_test_block_bitmap(pb->reserve, block) ||
++                       ext2fs_test_block_bitmap(pb->alloc_map, block));
++
++              retval = io_channel_read_blk(fs->io, orig, 1, pb->buf);
++              if (retval) {
++                      pb->error = retval;
++                      return BLOCK_ABORT;
++              }
++              retval = io_channel_write_blk(fs->io, block, 1, pb->buf);
++              if (retval) {
++                      pb->error = retval;
++                      return BLOCK_ABORT;
++              }
++              *block_nr = block;
++              ext2fs_mark_block_bitmap(pb->alloc_map, block);
++              ret = BLOCK_CHANGED;
++              if (pb->flags & EXT2_BMOVE_DEBUG)
++                      printf("ino=%ld, blockcnt=%lld, %d->%d\n", pb->ino,
++                             blockcnt, orig, block);
++      }
++      if (pb->add_dir) {
++              retval = ext2fs_add_dir_block(fs->dblist, pb->ino,
++                                            block, (int) blockcnt);
++              if (retval) {
++                      pb->error = retval;
++                      ret |= BLOCK_ABORT;
++              }
++      }
++      return ret;
++}
++
++errcode_t ext2fs_move_blocks(ext2_filsys fs,
++                           ext2fs_block_bitmap reserve,
++                           ext2fs_block_bitmap alloc_map,
++                           int flags)
++{
++      ext2_ino_t      ino;
++      struct ext2_inode inode;
++      errcode_t       retval;
++      struct process_block_struct pb;
++      ext2_inode_scan scan;
++      char            *block_buf;
++      
++      retval = ext2fs_open_inode_scan(fs, 0, &scan);
++      if (retval)
++              return retval;
++
++      pb.reserve = reserve;
++      pb.error = 0;
++      pb.alloc_map = alloc_map ? alloc_map : fs->block_map;
++      pb.flags = flags;
++      
++      retval = ext2fs_get_mem(fs->blocksize * 4, &block_buf);
++      if (retval)
++              return retval;
++      pb.buf = block_buf + fs->blocksize * 3;
++
++      /*
++       * If GET_DBLIST is set in the flags field, then we should
++       * gather directory block information while we're doing the
++       * block move.
++       */
++      if (flags & EXT2_BMOVE_GET_DBLIST) {
++              if (fs->dblist) {
++                      ext2fs_free_dblist(fs->dblist);
++                      fs->dblist = NULL;
++              }
++              retval = ext2fs_init_dblist(fs, 0);
++              if (retval)
++                      return retval;
++      }
++
++      retval = ext2fs_get_next_inode(scan, &ino, &inode);
++      if (retval)
++              return retval;
++      
++      while (ino) {
++              if ((inode.i_links_count == 0) ||
++                  !ext2fs_inode_has_valid_blocks(&inode))
++                      goto next;
++              
++              pb.ino = ino;
++              pb.inode = &inode;
++
++              pb.add_dir = (LINUX_S_ISDIR(inode.i_mode) &&
++                            flags & EXT2_BMOVE_GET_DBLIST);
++
++              retval = ext2fs_block_iterate2(fs, ino, 0, block_buf,
++                                            process_block, &pb);
++              if (retval)
++                      return retval;
++              if (pb.error)
++                      return pb.error;
++
++      next:
++              retval = ext2fs_get_next_inode(scan, &ino, &inode);
++              if (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE)
++                      goto next;
++      }
++      return 0;
++}
++
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/brel.h busybox/e2fsprogs/ext2fs/brel.h
+--- busybox-1.00/e2fsprogs/ext2fs/brel.h       1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/brel.h    2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,86 @@
++/*
++ * brel.h
++ * 
++ * Copyright (C) 1996, 1997 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++struct ext2_block_relocate_entry {
++      blk_t   new;
++      __s16   offset;
++      __u16   flags;
++      union {
++              blk_t           block_ref;
++              ext2_ino_t      inode_ref;
++      } owner;
++};
++
++#define RELOCATE_TYPE_REF  0x0007
++#define RELOCATE_BLOCK_REF 0x0001
++#define RELOCATE_INODE_REF 0x0002
++
++typedef struct ext2_block_relocation_table *ext2_brel;
++
++struct ext2_block_relocation_table {
++      __u32   magic;
++      char    *name;
++      blk_t   current;
++      void    *priv_data;
++
++      /*
++       * Add a block relocation entry.
++       */
++      errcode_t (*put)(ext2_brel brel, blk_t old,
++                            struct ext2_block_relocate_entry *ent);
++
++      /*
++       * Get a block relocation entry.
++       */
++      errcode_t (*get)(ext2_brel brel, blk_t old,
++                            struct ext2_block_relocate_entry *ent);
++
++      /*
++       * Initialize for iterating over the block relocation entries.
++       */
++      errcode_t (*start_iter)(ext2_brel brel);
++      
++      /*
++       * The iterator function for the inode relocation entries.
++       * Returns an inode number of 0 when out of entries.
++       */
++      errcode_t (*next)(ext2_brel brel, blk_t *old,
++                        struct ext2_block_relocate_entry *ent);
++
++      /*
++       * Move the inode relocation table from one block number to
++       * another.
++       */
++      errcode_t (*move)(ext2_brel brel, blk_t old, blk_t new);
++
++      /*
++       * Remove a block relocation entry.
++       */
++      errcode_t (*delete)(ext2_brel brel, blk_t old);
++
++
++      /*
++       * Free the block relocation table.
++       */
++      errcode_t (*free)(ext2_brel brel);
++};
++
++errcode_t ext2fs_brel_memarray_create(char *name, blk_t max_block,
++                                  ext2_brel *brel);
++
++#define ext2fs_brel_put(brel, old, ent) ((brel)->put((brel), old, ent))
++#define ext2fs_brel_get(brel, old, ent) ((brel)->get((brel), old, ent))
++#define ext2fs_brel_start_iter(brel) ((brel)->start_iter((brel)))
++#define ext2fs_brel_next(brel, old, ent) ((brel)->next((brel), old, ent))
++#define ext2fs_brel_move(brel, old, new) ((brel)->move((brel), old, new))
++#define ext2fs_brel_delete(brel, old) ((brel)->delete((brel), old))
++#define ext2fs_brel_free(brel) ((brel)->free((brel)))
++
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/brel_ma.c busybox/e2fsprogs/ext2fs/brel_ma.c
+--- busybox-1.00/e2fsprogs/ext2fs/brel_ma.c    1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/brel_ma.c 2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,197 @@
++/*
++ * brel_ma.c
++ * 
++ * Copyright (C) 1996, 1997 Theodore Ts'o.
++ *
++ * TODO: rewrite to not use a direct array!!!  (Fortunately this
++ * module isn't really used yet.)
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <fcntl.h>
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#if HAVE_ERRNO_H
++#include <errno.h>
++#endif
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++#include "brel.h"
++
++static errcode_t bma_put(ext2_brel brel, blk_t old,
++                      struct ext2_block_relocate_entry *ent);
++static errcode_t bma_get(ext2_brel brel, blk_t old,
++                      struct ext2_block_relocate_entry *ent);
++static errcode_t bma_start_iter(ext2_brel brel);
++static errcode_t bma_next(ext2_brel brel, blk_t *old,
++                       struct ext2_block_relocate_entry *ent);
++static errcode_t bma_move(ext2_brel brel, blk_t old, blk_t new);
++static errcode_t bma_delete(ext2_brel brel, blk_t old);
++static errcode_t bma_free(ext2_brel brel);
++
++struct brel_ma {
++      __u32 magic;
++      blk_t max_block;
++      struct ext2_block_relocate_entry *entries;
++};
++
++errcode_t ext2fs_brel_memarray_create(char *name, blk_t max_block,
++                                    ext2_brel *new_brel)
++{
++      ext2_brel               brel = 0;
++      errcode_t       retval;
++      struct brel_ma  *ma = 0;
++      size_t          size;
++
++      *new_brel = 0;
++
++      /*
++       * Allocate memory structures
++       */
++      retval = ext2fs_get_mem(sizeof(struct ext2_block_relocation_table),
++                              &brel);
++      if (retval)
++              goto errout;
++      memset(brel, 0, sizeof(struct ext2_block_relocation_table));
++      
++      retval = ext2fs_get_mem(strlen(name)+1, &brel->name);
++      if (retval)
++              goto errout;
++      strcpy(brel->name, name);
++      
++      retval = ext2fs_get_mem(sizeof(struct brel_ma), &ma);
++      if (retval)
++              goto errout;
++      memset(ma, 0, sizeof(struct brel_ma));
++      brel->priv_data = ma;
++      
++      size = (size_t) (sizeof(struct ext2_block_relocate_entry) *
++                       (max_block+1));
++      retval = ext2fs_get_mem(size, &ma->entries);
++      if (retval)
++              goto errout;
++      memset(ma->entries, 0, size);
++      ma->max_block = max_block;
++
++      /*
++       * Fill in the brel data structure
++       */
++      brel->put = bma_put;
++      brel->get = bma_get;
++      brel->start_iter = bma_start_iter;
++      brel->next = bma_next;
++      brel->move = bma_move;
++      brel->delete = bma_delete;
++      brel->free = bma_free;
++      
++      *new_brel = brel;
++      return 0;
++
++errout:
++      bma_free(brel);
++      return retval;
++}
++
++static errcode_t bma_put(ext2_brel brel, blk_t old,
++                      struct ext2_block_relocate_entry *ent)
++{
++      struct brel_ma  *ma;
++
++      ma = brel->priv_data;
++      if (old > ma->max_block)
++              return EXT2_ET_INVALID_ARGUMENT;
++      ma->entries[(unsigned)old] = *ent;
++      return 0;
++}
++
++static errcode_t bma_get(ext2_brel brel, blk_t old,
++                      struct ext2_block_relocate_entry *ent)
++{
++      struct brel_ma  *ma;
++
++      ma = brel->priv_data;
++      if (old > ma->max_block)
++              return EXT2_ET_INVALID_ARGUMENT;
++      if (ma->entries[(unsigned)old].new == 0)
++              return ENOENT;
++      *ent = ma->entries[old];
++      return 0;
++}
++
++static errcode_t bma_start_iter(ext2_brel brel)
++{
++      brel->current = 0;
++      return 0;
++}
++
++static errcode_t bma_next(ext2_brel brel, blk_t *old,
++                        struct ext2_block_relocate_entry *ent)
++{
++      struct brel_ma  *ma;
++
++      ma = brel->priv_data;
++      while (++brel->current < ma->max_block) {
++              if (ma->entries[(unsigned)brel->current].new == 0)
++                      continue;
++              *old = brel->current;
++              *ent = ma->entries[(unsigned)brel->current];
++              return 0;
++      }
++      *old = 0;
++      return 0;
++}
++
++static errcode_t bma_move(ext2_brel brel, blk_t old, blk_t new)
++{
++      struct brel_ma  *ma;
++
++      ma = brel->priv_data;
++      if ((old > ma->max_block) || (new > ma->max_block))
++              return EXT2_ET_INVALID_ARGUMENT;
++      if (ma->entries[(unsigned)old].new == 0)
++              return ENOENT;
++      ma->entries[(unsigned)new] = ma->entries[old];
++      ma->entries[(unsigned)old].new = 0;
++      return 0;
++}
++
++static errcode_t bma_delete(ext2_brel brel, blk_t old)
++{
++      struct brel_ma  *ma;
++
++      ma = brel->priv_data;
++      if (old > ma->max_block)
++              return EXT2_ET_INVALID_ARGUMENT;
++      if (ma->entries[(unsigned)old].new == 0)
++              return ENOENT;
++      ma->entries[(unsigned)old].new = 0;
++      return 0;
++}
++
++static errcode_t bma_free(ext2_brel brel)
++{
++      struct brel_ma  *ma;
++
++      if (!brel)
++              return 0;
++
++      ma = brel->priv_data;
++
++      if (ma) {
++              if (ma->entries)
++                      ext2fs_free_mem(&ma->entries);
++              ext2fs_free_mem(&ma);
++      }
++      if (brel->name)
++              ext2fs_free_mem(&brel->name);
++      ext2fs_free_mem(&brel);
++      return 0;
++}
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/check_desc.c busybox/e2fsprogs/ext2fs/check_desc.c
+--- busybox-1.00/e2fsprogs/ext2fs/check_desc.c 1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/check_desc.c      2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,68 @@
++/*
++ * check_desc.c --- Check the group descriptors of an ext2 filesystem
++ * 
++ * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <fcntl.h>
++#include <time.h>
++#if HAVE_SYS_STAT_H
++#include <sys/stat.h>
++#endif
++#if HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++/*
++ * This routine sanity checks the group descriptors
++ */
++errcode_t ext2fs_check_desc(ext2_filsys fs)
++{
++      dgrp_t i;
++      blk_t block = fs->super->s_first_data_block;
++      blk_t next;
++
++      EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
++
++      for (i = 0; i < fs->group_desc_count; i++) {
++              next = block + fs->super->s_blocks_per_group;
++              /*
++               * Check to make sure block bitmap for group is
++               * located within the group.
++               */
++              if (fs->group_desc[i].bg_block_bitmap < block ||
++                  fs->group_desc[i].bg_block_bitmap >= next)
++                      return EXT2_ET_GDESC_BAD_BLOCK_MAP;
++              /*
++               * Check to make sure inode bitmap for group is
++               * located within the group
++               */
++              if (fs->group_desc[i].bg_inode_bitmap < block ||
++                  fs->group_desc[i].bg_inode_bitmap >= next)
++                      return EXT2_ET_GDESC_BAD_INODE_MAP;
++              /*
++               * Check to make sure inode table for group is located
++               * within the group
++               */
++              if (fs->group_desc[i].bg_inode_table < block ||
++                  ((fs->group_desc[i].bg_inode_table +
++                    fs->inode_blocks_per_group) >= next))
++                      return EXT2_ET_GDESC_BAD_INODE_TABLE;
++              
++              block = next;
++      }
++      return 0;
++}
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/closefs.c busybox/e2fsprogs/ext2fs/closefs.c
+--- busybox-1.00/e2fsprogs/ext2fs/closefs.c    1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/closefs.c 2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,381 @@
++/*
++ * closefs.c --- close an ext2 filesystem
++ * 
++ * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <time.h>
++#include <string.h>
++
++#include "ext2_fs.h"
++#include "ext2fsP.h"
++
++static int test_root(int a, int b)
++{
++      if (a == 0)
++              return 1;
++      while (1) {
++              if (a == 1)
++                      return 1;
++              if (a % b)
++                      return 0;
++              a = a / b;
++      }
++}
++
++int ext2fs_bg_has_super(ext2_filsys fs, int group_block)
++{
++      if (!(fs->super->s_feature_ro_compat &
++            EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER))
++              return 1;
++
++      if (test_root(group_block, 3) || (test_root(group_block, 5)) ||
++          test_root(group_block, 7))
++              return 1;
++
++      return 0;
++}
++
++int ext2fs_super_and_bgd_loc(ext2_filsys fs, 
++                           dgrp_t group,
++                           blk_t *ret_super_blk,
++                           blk_t *ret_old_desc_blk,
++                           blk_t *ret_new_desc_blk,
++                           int *ret_meta_bg)
++{
++      blk_t   group_block, super_blk = 0, old_desc_blk = 0, new_desc_blk = 0;
++      unsigned int meta_bg, meta_bg_size;
++      int     numblocks, has_super;
++      int     old_desc_blocks;
++
++      group_block = fs->super->s_first_data_block +
++              (group * fs->super->s_blocks_per_group);
++
++      if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
++              old_desc_blocks = fs->super->s_first_meta_bg;
++      else
++              old_desc_blocks = 
++                      fs->desc_blocks + fs->super->s_reserved_gdt_blocks;
++
++      if (group == fs->group_desc_count-1) {
++              numblocks = (fs->super->s_blocks_count -
++                           fs->super->s_first_data_block) %
++                      fs->super->s_blocks_per_group;
++              if (!numblocks)
++                      numblocks = fs->super->s_blocks_per_group;
++      } else
++              numblocks = fs->super->s_blocks_per_group;
++
++      has_super = ext2fs_bg_has_super(fs, group);
++
++      if (has_super) {
++              super_blk = group_block;
++              numblocks--;
++      }
++      meta_bg_size = (fs->blocksize / sizeof (struct ext2_group_desc));
++      meta_bg = group / meta_bg_size;
++
++      if (!(fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) ||
++          (meta_bg < fs->super->s_first_meta_bg)) {
++              if (has_super) {
++                      old_desc_blk = group_block + 1;
++                      numblocks -= old_desc_blocks;
++              }
++      } else {
++              if (((group % meta_bg_size) == 0) ||
++                  ((group % meta_bg_size) == 1) ||
++                  ((group % meta_bg_size) == (meta_bg_size-1))) {
++                      if (has_super)
++                              has_super = 1;
++                      new_desc_blk = group_block + has_super;
++                      numblocks--;
++              }
++      }
++              
++      numblocks -= 2 + fs->inode_blocks_per_group;
++
++      if (ret_super_blk)
++              *ret_super_blk = super_blk;
++      if (ret_old_desc_blk)
++              *ret_old_desc_blk = old_desc_blk;
++      if (ret_new_desc_blk)
++              *ret_new_desc_blk = new_desc_blk;
++      if (ret_meta_bg)
++              *ret_meta_bg = meta_bg;
++      return (numblocks);
++}
++
++
++/*
++ * This function forces out the primary superblock.  We need to only
++ * write out those fields which we have changed, since if the
++ * filesystem is mounted, it may have changed some of the other
++ * fields.
++ *
++ * It takes as input a superblock which has already been byte swapped
++ * (if necessary).
++ *
++ */
++static errcode_t write_primary_superblock(ext2_filsys fs,
++                                        struct ext2_super_block *super)
++{
++      __u16           *old_super, *new_super;
++      int             check_idx, write_idx, size;
++      errcode_t       retval;
++
++      if (!fs->io->manager->write_byte || !fs->orig_super) {
++              io_channel_set_blksize(fs->io, SUPERBLOCK_OFFSET);
++              retval = io_channel_write_blk(fs->io, 1, -SUPERBLOCK_SIZE,
++                                            super);
++              io_channel_set_blksize(fs->io, fs->blocksize);
++              return retval;
++      }
++
++      old_super = (__u16 *) fs->orig_super;
++      new_super = (__u16 *) super;
++
++      for (check_idx = 0; check_idx < SUPERBLOCK_SIZE/2; check_idx++) {
++              if (old_super[check_idx] == new_super[check_idx])
++                      continue;
++              write_idx = check_idx;
++              for (check_idx++; check_idx < SUPERBLOCK_SIZE/2; check_idx++)
++                      if (old_super[check_idx] == new_super[check_idx])
++                              break;
++              size = 2 * (check_idx - write_idx);
++#if 0
++              printf("Writing %d bytes starting at %d\n",
++                     size, write_idx*2);
++#endif
++              retval = io_channel_write_byte(fs->io,
++                             SUPERBLOCK_OFFSET + (2 * write_idx), size,
++                                             new_super + write_idx);
++              if (retval)
++                      return retval;
++      }
++      memcpy(fs->orig_super, super, SUPERBLOCK_SIZE);
++      return 0;
++}
++
++
++/*
++ * Updates the revision to EXT2_DYNAMIC_REV
++ */
++void ext2fs_update_dynamic_rev(ext2_filsys fs)
++{
++      struct ext2_super_block *sb = fs->super;
++
++      if (sb->s_rev_level > EXT2_GOOD_OLD_REV)
++              return;
++
++      sb->s_rev_level = EXT2_DYNAMIC_REV;
++      sb->s_first_ino = EXT2_GOOD_OLD_FIRST_INO;
++      sb->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE;
++      /* s_uuid is handled by e2fsck already */
++      /* other fields should be left alone */
++}
++
++static errcode_t write_backup_super(ext2_filsys fs, dgrp_t group,
++                                  blk_t group_block,
++                                  struct ext2_super_block *super_shadow)
++{
++      dgrp_t  sgrp = group;
++      
++      if (sgrp > ((1 << 16) - 1))
++              sgrp = (1 << 16) - 1;
++#ifdef EXT2FS_ENABLE_SWAPFS
++      if (fs->flags & EXT2_FLAG_SWAP_BYTES)
++              super_shadow->s_block_group_nr = ext2fs_swab16(sgrp);
++      else
++#endif
++              fs->super->s_block_group_nr = sgrp;
++
++      return io_channel_write_blk(fs->io, group_block, -SUPERBLOCK_SIZE, 
++                                  super_shadow);
++}
++
++
++errcode_t ext2fs_flush(ext2_filsys fs)
++{
++      dgrp_t          i,j;
++      blk_t           group_block;
++      errcode_t       retval;
++      unsigned long   fs_state;
++      struct ext2_super_block *super_shadow = 0;
++      struct ext2_group_desc *group_shadow = 0;
++      struct ext2_group_desc *s, *t;
++      char    *group_ptr;
++      int     old_desc_blocks;
++      
++      EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
++
++      fs_state = fs->super->s_state;
++
++      fs->super->s_wtime = time(NULL);
++      fs->super->s_block_group_nr = 0;
++#ifdef EXT2FS_ENABLE_SWAPFS
++      if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
++              retval = EXT2_ET_NO_MEMORY;
++              retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &super_shadow);
++              if (retval)
++                      goto errout;
++              retval = ext2fs_get_mem((size_t)(fs->blocksize *
++                                               fs->desc_blocks),
++                                      &group_shadow);
++              if (retval)
++                      goto errout;
++              memset(group_shadow, 0, (size_t) fs->blocksize *
++                     fs->desc_blocks);
++
++              /* swap the group descriptors */
++              for (j=0, s=fs->group_desc, t=group_shadow;
++                   j < fs->group_desc_count; j++, t++, s++) {
++                      *t = *s;
++                      ext2fs_swap_group_desc(t);
++              }
++      } else {
++              super_shadow = fs->super;
++              group_shadow = fs->group_desc;
++      }
++#else
++      super_shadow = fs->super;
++      group_shadow = fs->group_desc;
++#endif
++      
++      /*
++       * If this is an external journal device, don't write out the
++       * block group descriptors or any of the backup superblocks
++       */
++      if (fs->super->s_feature_incompat &
++          EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
++              goto write_primary_superblock_only;
++
++      /*
++       * Set the state of the FS to be non-valid.  (The state has
++       * already been backed up earlier, and will be restored after
++       * we write out the backup superblocks.)
++       */
++      fs->super->s_state &= ~EXT2_VALID_FS;
++#ifdef EXT2FS_ENABLE_SWAPFS
++      if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
++              *super_shadow = *fs->super;
++              ext2fs_swap_super(super_shadow);
++      }
++#endif
++
++      /*
++       * Write out the master group descriptors, and the backup
++       * superblocks and group descriptors.
++       */
++      group_block = fs->super->s_first_data_block;
++      group_ptr = (char *) group_shadow;
++      if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
++              old_desc_blocks = fs->super->s_first_meta_bg;
++      else
++              old_desc_blocks = fs->desc_blocks;
++
++      for (i = 0; i < fs->group_desc_count; i++) {
++              blk_t   super_blk, old_desc_blk, new_desc_blk;
++              int     meta_bg;
++
++              ext2fs_super_and_bgd_loc(fs, i, &super_blk, &old_desc_blk, 
++                                       &new_desc_blk, &meta_bg);
++
++              if (!(fs->flags & EXT2_FLAG_MASTER_SB_ONLY) &&i && super_blk) {
++                      retval = write_backup_super(fs, i, super_blk,
++                                                  super_shadow);
++                      if (retval)
++                              goto errout;
++              }
++              if (fs->flags & EXT2_FLAG_SUPER_ONLY)
++                      continue;
++              if ((old_desc_blk) && 
++                  (!(fs->flags & EXT2_FLAG_MASTER_SB_ONLY) || (i == 0))) {
++                      retval = io_channel_write_blk(fs->io,
++                            old_desc_blk, old_desc_blocks, group_ptr);
++                      if (retval)
++                              goto errout;
++              }
++              if (new_desc_blk) {
++                      retval = io_channel_write_blk(fs->io, new_desc_blk,
++                              1, group_ptr + (meta_bg*fs->blocksize));
++                      if (retval)
++                              goto errout;
++              }
++      }
++      fs->super->s_block_group_nr = 0;
++      fs->super->s_state = fs_state;
++#ifdef EXT2FS_ENABLE_SWAPFS
++      if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
++              *super_shadow = *fs->super;
++              ext2fs_swap_super(super_shadow);
++      }
++#endif
++
++      /*
++       * If the write_bitmaps() function is present, call it to
++       * flush the bitmaps.  This is done this way so that a simple
++       * program that doesn't mess with the bitmaps doesn't need to
++       * drag in the bitmaps.c code.
++       */
++      if (fs->write_bitmaps) {
++              retval = fs->write_bitmaps(fs);
++              if (retval)
++                      goto errout;
++      }
++
++write_primary_superblock_only:
++      /*
++       * Write out master superblock.  This has to be done
++       * separately, since it is located at a fixed location
++       * (SUPERBLOCK_OFFSET).  We flush all other pending changes
++       * out to disk first, just to avoid a race condition with an
++       * insy-tinsy window....
++       */
++      retval = io_channel_flush(fs->io);
++      retval = write_primary_superblock(fs, super_shadow);
++      if (retval)
++              goto errout;
++
++      fs->flags &= ~EXT2_FLAG_DIRTY;
++
++      retval = io_channel_flush(fs->io);
++errout:
++      fs->super->s_state = fs_state;
++      if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
++              if (super_shadow)
++                      ext2fs_free_mem(&super_shadow);
++              if (group_shadow)
++                      ext2fs_free_mem(&group_shadow);
++      }
++      return retval;
++}
++
++errcode_t ext2fs_close(ext2_filsys fs)
++{
++      errcode_t       retval;
++      
++      EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
++
++      if (fs->flags & EXT2_FLAG_DIRTY) {
++              retval = ext2fs_flush(fs);
++              if (retval)
++                      return retval;
++      }
++      if (fs->write_bitmaps) {
++              retval = fs->write_bitmaps(fs);
++              if (retval)
++                      return retval;
++      }
++      ext2fs_free(fs);
++      return 0;
++}
++
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/cmp_bitmaps.c busybox/e2fsprogs/ext2fs/cmp_bitmaps.c
+--- busybox-1.00/e2fsprogs/ext2fs/cmp_bitmaps.c        1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/cmp_bitmaps.c     2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,72 @@
++/*
++ * cmp_bitmaps.c --- routines to compare inode and block bitmaps.
++ *
++ * Copyright (C) 1995 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <fcntl.h>
++#include <time.h>
++#if HAVE_SYS_STAT_H
++#include <sys/stat.h>
++#endif
++#if HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++errcode_t ext2fs_compare_block_bitmap(ext2fs_block_bitmap bm1,
++                                    ext2fs_block_bitmap bm2)
++{
++      blk_t   i;
++      
++      EXT2_CHECK_MAGIC(bm1, EXT2_ET_MAGIC_BLOCK_BITMAP);
++      EXT2_CHECK_MAGIC(bm2, EXT2_ET_MAGIC_BLOCK_BITMAP);
++
++      if ((bm1->start != bm2->start) ||
++          (bm1->end != bm2->end) ||
++          (memcmp(bm1->bitmap, bm2->bitmap,
++                  (size_t) (bm1->end - bm1->start)/8)))
++              return EXT2_ET_NEQ_BLOCK_BITMAP;
++
++      for (i = bm1->end - ((bm1->end - bm1->start) % 8); i <= bm1->end; i++)
++              if (ext2fs_fast_test_block_bitmap(bm1, i) !=
++                  ext2fs_fast_test_block_bitmap(bm2, i))
++                      return EXT2_ET_NEQ_BLOCK_BITMAP;
++
++      return 0;
++}
++
++errcode_t ext2fs_compare_inode_bitmap(ext2fs_inode_bitmap bm1,
++                                    ext2fs_inode_bitmap bm2)
++{
++      ext2_ino_t      i;
++      
++      EXT2_CHECK_MAGIC(bm1, EXT2_ET_MAGIC_INODE_BITMAP);
++      EXT2_CHECK_MAGIC(bm2, EXT2_ET_MAGIC_INODE_BITMAP);
++
++      if ((bm1->start != bm2->start) ||
++          (bm1->end != bm2->end) ||
++          (memcmp(bm1->bitmap, bm2->bitmap,
++                  (size_t) (bm1->end - bm1->start)/8)))
++              return EXT2_ET_NEQ_INODE_BITMAP;
++
++      for (i = bm1->end - ((bm1->end - bm1->start) % 8); i <= bm1->end; i++)
++              if (ext2fs_fast_test_inode_bitmap(bm1, i) !=
++                  ext2fs_fast_test_inode_bitmap(bm2, i))
++                      return EXT2_ET_NEQ_INODE_BITMAP;
++
++      return 0;
++}
++
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/dblist.c busybox/e2fsprogs/ext2fs/dblist.c
+--- busybox-1.00/e2fsprogs/ext2fs/dblist.c     1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/dblist.c  2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,260 @@
++/*
++ * dblist.c -- directory block list functions
++ * 
++ * Copyright 1997 by Theodore Ts'o
++ * 
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ * 
++ */
++
++#include <stdio.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <string.h>
++#include <time.h>
++
++#include "ext2_fs.h"
++#include "ext2fsP.h"
++
++static EXT2_QSORT_TYPE dir_block_cmp(const void *a, const void *b);
++
++/*
++ * Returns the number of directories in the filesystem as reported by
++ * the group descriptors.  Of course, the group descriptors could be
++ * wrong!
++ */
++errcode_t ext2fs_get_num_dirs(ext2_filsys fs, ext2_ino_t *ret_num_dirs)
++{
++      dgrp_t  i;
++      ext2_ino_t      num_dirs, max_dirs;
++
++      EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
++      
++      num_dirs = 0;
++      max_dirs = fs->super->s_inodes_per_group;
++      for (i = 0; i < fs->group_desc_count; i++) {
++              if (fs->group_desc[i].bg_used_dirs_count > max_dirs)
++                      num_dirs += max_dirs / 8;
++              else
++                      num_dirs += fs->group_desc[i].bg_used_dirs_count;
++      }
++      if (num_dirs > fs->super->s_inodes_count)
++              num_dirs = fs->super->s_inodes_count;
++
++      *ret_num_dirs = num_dirs;
++
++      return 0;
++}
++
++/*
++ * helper function for making a new directory block list (for
++ * initialize and copy).
++ */
++static errcode_t make_dblist(ext2_filsys fs, ext2_ino_t size, ext2_ino_t count,
++                           struct ext2_db_entry *list,
++                           ext2_dblist *ret_dblist)
++{
++      ext2_dblist     dblist;
++      errcode_t       retval;
++      size_t          len;
++
++      EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
++
++      if ((ret_dblist == 0) && fs->dblist &&
++          (fs->dblist->magic == EXT2_ET_MAGIC_DBLIST))
++              return 0;
++
++      retval = ext2fs_get_mem(sizeof(struct ext2_struct_dblist), &dblist);
++      if (retval)
++              return retval;
++      memset(dblist, 0, sizeof(struct ext2_struct_dblist));
++
++      dblist->magic = EXT2_ET_MAGIC_DBLIST;
++      dblist->fs = fs;
++      if (size)
++              dblist->size = size;
++      else {
++              retval = ext2fs_get_num_dirs(fs, &dblist->size);
++              if (retval)
++                      goto cleanup;
++              dblist->size = (dblist->size * 2) + 12;
++      }
++      len = (size_t) sizeof(struct ext2_db_entry) * dblist->size;
++      dblist->count = count;
++      retval = ext2fs_get_mem(len, &dblist->list);
++      if (retval)
++              goto cleanup;
++      
++      if (list)
++              memcpy(dblist->list, list, len);
++      else
++              memset(dblist->list, 0, len);
++      if (ret_dblist)
++              *ret_dblist = dblist;
++      else
++              fs->dblist = dblist;
++      return 0;
++cleanup:
++      if (dblist)
++              ext2fs_free_mem(&dblist);
++      return retval;
++}
++
++/*
++ * Initialize a directory block list
++ */
++errcode_t ext2fs_init_dblist(ext2_filsys fs, ext2_dblist *ret_dblist)
++{
++      ext2_dblist     dblist;
++      errcode_t       retval;
++
++      retval = make_dblist(fs, 0, 0, 0, &dblist);
++      if (retval)
++              return retval;
++
++      dblist->sorted = 1;
++      if (ret_dblist)
++              *ret_dblist = dblist;
++      else
++              fs->dblist = dblist;
++
++      return 0;
++}
++
++/*
++ * Copy a directory block list
++ */
++errcode_t ext2fs_copy_dblist(ext2_dblist src, ext2_dblist *dest)
++{
++      ext2_dblist     dblist;
++      errcode_t       retval;
++
++      retval = make_dblist(src->fs, src->size, src->count, src->list,
++                           &dblist);
++      if (retval)
++              return retval;
++      dblist->sorted = src->sorted;
++      *dest = dblist;
++      return 0;
++}
++
++/*
++ * Close a directory block list
++ *
++ * (moved to closefs.c)
++ */
++
++
++/*
++ * Add a directory block to the directory block list
++ */
++errcode_t ext2fs_add_dir_block(ext2_dblist dblist, ext2_ino_t ino, blk_t blk,
++                             int blockcnt)
++{
++      struct ext2_db_entry    *new_entry;
++      errcode_t               retval;
++      unsigned long           old_size;
++      
++      EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
++
++      if (dblist->count >= dblist->size) {
++              old_size = dblist->size * sizeof(struct ext2_db_entry);
++              dblist->size += 100;
++              retval = ext2fs_resize_mem(old_size, (size_t) dblist->size *
++                                         sizeof(struct ext2_db_entry),
++                                         &dblist->list);
++              if (retval) {
++                      dblist->size -= 100;
++                      return retval;
++              }
++      }
++      new_entry = dblist->list + ( (int) dblist->count++);
++      new_entry->blk = blk;
++      new_entry->ino = ino;
++      new_entry->blockcnt = blockcnt;
++
++      dblist->sorted = 0;
++
++      return 0;
++}
++
++/*
++ * Change the directory block to the directory block list
++ */
++errcode_t ext2fs_set_dir_block(ext2_dblist dblist, ext2_ino_t ino, blk_t blk,
++                             int blockcnt)
++{
++      dgrp_t                  i;
++      
++      EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
++
++      for (i=0; i < dblist->count; i++) {
++              if ((dblist->list[i].ino != ino) ||
++                  (dblist->list[i].blockcnt != blockcnt))
++                      continue;
++              dblist->list[i].blk = blk;
++              dblist->sorted = 0;
++              return 0;
++      }
++      return EXT2_ET_DB_NOT_FOUND;
++}
++
++void ext2fs_dblist_sort(ext2_dblist dblist,
++                      EXT2_QSORT_TYPE (*sortfunc)(const void *,
++                                                  const void *))
++{
++      if (!sortfunc)
++              sortfunc = dir_block_cmp;
++      qsort(dblist->list, (size_t) dblist->count,
++            sizeof(struct ext2_db_entry), sortfunc);
++      dblist->sorted = 1;
++}
++
++/*
++ * This function iterates over the directory block list
++ */
++errcode_t ext2fs_dblist_iterate(ext2_dblist dblist,
++                              int (*func)(ext2_filsys fs,
++                                          struct ext2_db_entry *db_info,
++                                          void        *priv_data),
++                              void *priv_data)
++{
++      ext2_ino_t      i;
++      int             ret;
++      
++      EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
++
++      if (!dblist->sorted)
++              ext2fs_dblist_sort(dblist, 0);
++      for (i=0; i < dblist->count; i++) {
++              ret = (*func)(dblist->fs, &dblist->list[(int)i], priv_data);
++              if (ret & DBLIST_ABORT)
++                      return 0;
++      }
++      return 0;
++}
++
++static EXT2_QSORT_TYPE dir_block_cmp(const void *a, const void *b)
++{
++      const struct ext2_db_entry *db_a =
++              (const struct ext2_db_entry *) a;
++      const struct ext2_db_entry *db_b =
++              (const struct ext2_db_entry *) b;
++
++      if (db_a->blk != db_b->blk)
++              return (int) (db_a->blk - db_b->blk);
++      
++      if (db_a->ino != db_b->ino)
++              return (int) (db_a->ino - db_b->ino);
++
++      return (int) (db_a->blockcnt - db_b->blockcnt);
++}
++
++int ext2fs_dblist_count(ext2_dblist dblist)
++{
++      return (int) dblist->count;
++}
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/dblist_dir.c busybox/e2fsprogs/ext2fs/dblist_dir.c
+--- busybox-1.00/e2fsprogs/ext2fs/dblist_dir.c 1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/dblist_dir.c      2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,75 @@
++/*
++ * dblist_dir.c --- iterate by directory entry
++ *
++ * Copyright 1997 by Theodore Ts'o
++ * 
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ * 
++ */
++
++#include <stdio.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <string.h>
++#include <time.h>
++
++#include "ext2_fs.h"
++#include "ext2fsP.h"
++
++static int db_dir_proc(ext2_filsys fs, struct ext2_db_entry *db_info,
++                     void *priv_data);
++
++errcode_t ext2fs_dblist_dir_iterate(ext2_dblist dblist,
++                                  int flags,
++                                  char        *block_buf,
++                                  int (*func)(ext2_ino_t dir,
++                                              int     entry,
++                                              struct ext2_dir_entry *dirent,
++                                              int     offset,
++                                              int     blocksize,
++                                              char    *buf,
++                                              void    *priv_data),
++                                  void *priv_data)
++{
++      errcode_t               retval;
++      struct dir_context      ctx;
++
++      EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
++
++      ctx.dir = 0;
++      ctx.flags = flags;
++      if (block_buf)
++              ctx.buf = block_buf;
++      else {
++              retval = ext2fs_get_mem(dblist->fs->blocksize, &ctx.buf);
++              if (retval)
++                      return retval;
++      }
++      ctx.func = func;
++      ctx.priv_data = priv_data;
++      ctx.errcode = 0;
++
++      retval = ext2fs_dblist_iterate(dblist, db_dir_proc, &ctx);
++      
++      if (!block_buf)
++              ext2fs_free_mem(&ctx.buf);
++      if (retval)
++              return retval;
++      return ctx.errcode;
++}
++
++static int db_dir_proc(ext2_filsys fs, struct ext2_db_entry *db_info,
++                     void *priv_data)
++{
++      struct dir_context      *ctx;
++
++      ctx = (struct dir_context *) priv_data;
++      ctx->dir = db_info->ino;
++      
++      return ext2fs_process_dir_block(fs, &db_info->blk,
++                                      db_info->blockcnt, 0, 0, priv_data);
++}
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/dir_iterate.c busybox/e2fsprogs/ext2fs/dir_iterate.c
+--- busybox-1.00/e2fsprogs/ext2fs/dir_iterate.c        1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/dir_iterate.c     2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,219 @@
++/*
++ * dir_iterate.c --- ext2fs directory iteration operations
++ * 
++ * Copyright (C) 1993, 1994, 1994, 1995, 1996, 1997 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#if HAVE_ERRNO_H
++#include <errno.h>
++#endif
++
++#include "ext2_fs.h"
++#include "ext2fsP.h"
++
++/*
++ * This function checks to see whether or not a potential deleted
++ * directory entry looks valid.  What we do is check the deleted entry
++ * and each successive entry to make sure that they all look valid and
++ * that the last deleted entry ends at the beginning of the next
++ * undeleted entry.  Returns 1 if the deleted entry looks valid, zero
++ * if not valid.
++ */
++static int ext2fs_validate_entry(char *buf, int offset, int final_offset)
++{
++      struct ext2_dir_entry *dirent;
++      
++      while (offset < final_offset) {
++              dirent = (struct ext2_dir_entry *)(buf + offset);
++              offset += dirent->rec_len;
++              if ((dirent->rec_len < 8) ||
++                  ((dirent->rec_len % 4) != 0) ||
++                  (((dirent->name_len & 0xFF)+8) > dirent->rec_len))
++                      return 0;
++      }
++      return (offset == final_offset);
++}
++
++errcode_t ext2fs_dir_iterate2(ext2_filsys fs,
++                            ext2_ino_t dir,
++                            int flags,
++                            char *block_buf,
++                            int (*func)(ext2_ino_t    dir,
++                                        int           entry,
++                                        struct ext2_dir_entry *dirent,
++                                        int   offset,
++                                        int   blocksize,
++                                        char  *buf,
++                                        void  *priv_data),
++                            void *priv_data)
++{
++      struct          dir_context     ctx;
++      errcode_t       retval;
++      
++      EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
++
++      retval = ext2fs_check_directory(fs, dir);
++      if (retval)
++              return retval;
++      
++      ctx.dir = dir;
++      ctx.flags = flags;
++      if (block_buf)
++              ctx.buf = block_buf;
++      else {
++              retval = ext2fs_get_mem(fs->blocksize, &ctx.buf);
++              if (retval)
++                      return retval;
++      }
++      ctx.func = func;
++      ctx.priv_data = priv_data;
++      ctx.errcode = 0;
++      retval = ext2fs_block_iterate2(fs, dir, 0, 0,
++                                     ext2fs_process_dir_block, &ctx);
++      if (!block_buf)
++              ext2fs_free_mem(&ctx.buf);
++      if (retval)
++              return retval;
++      return ctx.errcode;
++}
++
++struct xlate {
++      int (*func)(struct ext2_dir_entry *dirent,
++                  int         offset,
++                  int         blocksize,
++                  char        *buf,
++                  void        *priv_data);
++      void *real_private;
++};
++
++static int xlate_func(ext2_ino_t dir EXT2FS_ATTR((unused)),
++                    int entry EXT2FS_ATTR((unused)),
++                    struct ext2_dir_entry *dirent, int offset,
++                    int blocksize, char *buf, void *priv_data)
++{
++      struct xlate *xl = (struct xlate *) priv_data;
++
++      return (*xl->func)(dirent, offset, blocksize, buf, xl->real_private);
++}
++
++extern errcode_t ext2fs_dir_iterate(ext2_filsys fs, 
++                            ext2_ino_t dir,
++                            int flags,
++                            char *block_buf,
++                            int (*func)(struct ext2_dir_entry *dirent,
++                                        int   offset,
++                                        int   blocksize,
++                                        char  *buf,
++                                        void  *priv_data),
++                            void *priv_data)
++{
++      struct xlate xl;
++      
++      xl.real_private = priv_data;
++      xl.func = func;
++
++      return ext2fs_dir_iterate2(fs, dir, flags, block_buf,
++                                 xlate_func, &xl);
++}
++
++
++/*
++ * Helper function which is private to this module.  Used by
++ * ext2fs_dir_iterate() and ext2fs_dblist_dir_iterate()
++ */
++int ext2fs_process_dir_block(ext2_filsys fs,
++                           blk_t      *blocknr,
++                           e2_blkcnt_t blockcnt,
++                           blk_t      ref_block EXT2FS_ATTR((unused)),
++                           int        ref_offset EXT2FS_ATTR((unused)),
++                           void       *priv_data)
++{
++      struct dir_context *ctx = (struct dir_context *) priv_data;
++      unsigned int    offset = 0;
++      unsigned int    next_real_entry = 0;
++      int             ret = 0;
++      int             changed = 0;
++      int             do_abort = 0;
++      int             entry, size;
++      struct ext2_dir_entry *dirent;
++
++      if (blockcnt < 0)
++              return 0;
++
++      entry = blockcnt ? DIRENT_OTHER_FILE : DIRENT_DOT_FILE;
++      
++      ctx->errcode = ext2fs_read_dir_block(fs, *blocknr, ctx->buf);
++      if (ctx->errcode)
++              return BLOCK_ABORT;
++
++      while (offset < fs->blocksize) {
++              dirent = (struct ext2_dir_entry *) (ctx->buf + offset);
++              if (((offset + dirent->rec_len) > fs->blocksize) ||
++                  (dirent->rec_len < 8) ||
++                  ((dirent->rec_len % 4) != 0) ||
++                  (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) {
++                      ctx->errcode = EXT2_ET_DIR_CORRUPTED;
++                      return BLOCK_ABORT;
++              }
++              if (!dirent->inode &&
++                  !(ctx->flags & DIRENT_FLAG_INCLUDE_EMPTY))
++                      goto next;
++
++              ret = (ctx->func)(ctx->dir,
++                                (next_real_entry > offset) ?
++                                DIRENT_DELETED_FILE : entry,
++                                dirent, offset,
++                                fs->blocksize, ctx->buf,
++                                ctx->priv_data);
++              if (entry < DIRENT_OTHER_FILE)
++                      entry++;
++                      
++              if (ret & DIRENT_CHANGED)
++                      changed++;
++              if (ret & DIRENT_ABORT) {
++                      do_abort++;
++                      break;
++              }
++next:         
++              if (next_real_entry == offset)
++                      next_real_entry += dirent->rec_len;
++ 
++              if (ctx->flags & DIRENT_FLAG_INCLUDE_REMOVED) {
++                      size = ((dirent->name_len & 0xFF) + 11) & ~3;
++
++                      if (dirent->rec_len != size)  {
++                              unsigned int final_offset;
++
++                              final_offset = offset + dirent->rec_len;
++                              offset += size;
++                              while (offset < final_offset &&
++                                     !ext2fs_validate_entry(ctx->buf,
++                                                            offset,
++                                                            final_offset))
++                                      offset += 4;
++                              continue;
++                      }
++              }
++              offset += dirent->rec_len;
++      }
++
++      if (changed) {
++              ctx->errcode = ext2fs_write_dir_block(fs, *blocknr, ctx->buf);
++              if (ctx->errcode)
++                      return BLOCK_ABORT;
++      }
++      if (do_abort)
++              return BLOCK_ABORT;
++      return 0;
++}
++
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/dirblock.c busybox/e2fsprogs/ext2fs/dirblock.c
+--- busybox-1.00/e2fsprogs/ext2fs/dirblock.c   1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/dirblock.c        2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,130 @@
++/*
++ * dirblock.c --- directory block routines.
++ * 
++ * Copyright (C) 1995, 1996 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <string.h>
++#include <time.h>
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++errcode_t ext2fs_read_dir_block2(ext2_filsys fs, blk_t block,
++                               void *buf, int flags EXT2FS_ATTR((unused)))
++{
++      errcode_t       retval;
++      char            *p, *end;
++      struct ext2_dir_entry *dirent;
++      unsigned int    name_len, rec_len, do_swap;
++      
++
++      retval = io_channel_read_blk(fs->io, block, 1, buf);
++      if (retval)
++              return retval;
++#ifdef EXT2FS_ENABLE_SWAPFS
++      do_swap = (fs->flags & (EXT2_FLAG_SWAP_BYTES|
++                              EXT2_FLAG_SWAP_BYTES_READ)) != 0;
++#endif
++      p = (char *) buf;
++      end = (char *) buf + fs->blocksize;
++      while (p < end-8) {
++              dirent = (struct ext2_dir_entry *) p;
++#ifdef EXT2FS_ENABLE_SWAPFS
++              if (do_swap) {
++                      dirent->inode = ext2fs_swab32(dirent->inode);
++                      dirent->rec_len = ext2fs_swab16(dirent->rec_len);
++                      dirent->name_len = ext2fs_swab16(dirent->name_len);
++              }
++#endif
++              name_len = dirent->name_len;
++#ifdef WORDS_BIGENDIAN
++              if (flags & EXT2_DIRBLOCK_V2_STRUCT)
++                      dirent->name_len = ext2fs_swab16(dirent->name_len);
++#endif
++              rec_len = dirent->rec_len;
++              if ((rec_len < 8) || (rec_len % 4)) {
++                      rec_len = 8;
++                      retval = EXT2_ET_DIR_CORRUPTED;
++              }
++              if (((name_len & 0xFF) + 8) > dirent->rec_len)
++                      retval = EXT2_ET_DIR_CORRUPTED;
++              p += rec_len;
++      }
++      return retval;
++}
++
++errcode_t ext2fs_read_dir_block(ext2_filsys fs, blk_t block,
++                               void *buf)
++{
++      return ext2fs_read_dir_block2(fs, block, buf, 0);
++}
++
++
++errcode_t ext2fs_write_dir_block2(ext2_filsys fs, blk_t block,
++                                void *inbuf, int flags EXT2FS_ATTR((unused)))
++{
++#ifdef EXT2FS_ENABLE_SWAPFS
++      int             do_swap = 0;
++      errcode_t       retval;
++      char            *p, *end;
++      char            *buf = 0;
++      struct ext2_dir_entry *dirent;
++
++      if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
++          (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
++              do_swap = 1;
++
++#ifndef WORDS_BIGENDIAN
++      if (!do_swap)
++              return io_channel_write_blk(fs->io, block, 1, (char *) inbuf);
++#endif
++
++      retval = ext2fs_get_mem(fs->blocksize, &buf);
++      if (retval)
++              return retval;
++      memcpy(buf, inbuf, fs->blocksize);
++      p = buf;
++      end = buf + fs->blocksize;
++      while (p < end) {
++              dirent = (struct ext2_dir_entry *) p;
++              if ((dirent->rec_len < 8) ||
++                  (dirent->rec_len % 4)) {
++                      ext2fs_free_mem(&buf);
++                      return (EXT2_ET_DIR_CORRUPTED);
++              }
++              p += dirent->rec_len;
++              if (do_swap) {
++                      dirent->inode = ext2fs_swab32(dirent->inode);
++                      dirent->rec_len = ext2fs_swab16(dirent->rec_len);
++                      dirent->name_len = ext2fs_swab16(dirent->name_len);
++              }
++#ifdef WORDS_BIGENDIAN 
++              if (flags & EXT2_DIRBLOCK_V2_STRUCT)
++                      dirent->name_len = ext2fs_swab16(dirent->name_len);
++#endif
++      }
++      retval = io_channel_write_blk(fs->io, block, 1, buf);
++      ext2fs_free_mem(&buf);
++      return retval;
++#else
++      return io_channel_write_blk(fs->io, block, 1, (char *) inbuf);
++#endif
++}
++
++
++errcode_t ext2fs_write_dir_block(ext2_filsys fs, blk_t block,
++                               void *inbuf)
++{
++      return ext2fs_write_dir_block2(fs, block, inbuf, 0);
++}
++
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/dirhash.c busybox/e2fsprogs/ext2fs/dirhash.c
+--- busybox-1.00/e2fsprogs/ext2fs/dirhash.c    1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/dirhash.c 2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,233 @@
++/*
++ * dirhash.c -- Calculate the hash of a directory entry
++ *
++ * Copyright (c) 2001  Daniel Phillips
++ * 
++ * Copyright (c) 2002 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <string.h>
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++/*
++ * Keyed 32-bit hash function using TEA in a Davis-Meyer function
++ *   H0 = Key
++ *   Hi = E Mi(Hi-1) + Hi-1
++ *
++ * (see Applied Cryptography, 2nd edition, p448).
++ *
++ * Jeremy Fitzhardinge <jeremy@zip.com.au> 1998
++ * 
++ * This code is made available under the terms of the GPL
++ */
++#define DELTA 0x9E3779B9
++
++static void TEA_transform(__u32 buf[4], __u32 const in[])
++{
++      __u32   sum = 0;
++      __u32   b0 = buf[0], b1 = buf[1];
++      __u32   a = in[0], b = in[1], c = in[2], d = in[3];
++      int     n = 16;
++
++      do {                                                    
++              sum += DELTA;                                   
++              b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b); 
++              b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d); 
++      } while(--n);
++
++      buf[0] += b0;
++      buf[1] += b1;
++}
++
++/* F, G and H are basic MD4 functions: selection, majority, parity */
++#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
++#define G(x, y, z) (((x) & (y)) + (((x) ^ (y)) & (z)))
++#define H(x, y, z) ((x) ^ (y) ^ (z))
++
++/*
++ * The generic round function.  The application is so specific that
++ * we don't bother protecting all the arguments with parens, as is generally
++ * good macro practice, in favor of extra legibility.
++ * Rotation is separate from addition to prevent recomputation
++ */
++#define ROUND(f, a, b, c, d, x, s)    \
++      (a += f(b, c, d) + x, a = (a << s) | (a >> (32-s)))
++#define K1 0
++#define K2 013240474631UL
++#define K3 015666365641UL
++
++/*
++ * Basic cut-down MD4 transform.  Returns only 32 bits of result.
++ */
++static void halfMD4Transform (__u32 buf[4], __u32 const in[])
++{
++      __u32   a = buf[0], b = buf[1], c = buf[2], d = buf[3];
++
++      /* Round 1 */
++      ROUND(F, a, b, c, d, in[0] + K1,  3);
++      ROUND(F, d, a, b, c, in[1] + K1,  7);
++      ROUND(F, c, d, a, b, in[2] + K1, 11);
++      ROUND(F, b, c, d, a, in[3] + K1, 19);
++      ROUND(F, a, b, c, d, in[4] + K1,  3);
++      ROUND(F, d, a, b, c, in[5] + K1,  7);
++      ROUND(F, c, d, a, b, in[6] + K1, 11);
++      ROUND(F, b, c, d, a, in[7] + K1, 19);
++
++      /* Round 2 */
++      ROUND(G, a, b, c, d, in[1] + K2,  3);
++      ROUND(G, d, a, b, c, in[3] + K2,  5);
++      ROUND(G, c, d, a, b, in[5] + K2,  9);
++      ROUND(G, b, c, d, a, in[7] + K2, 13);
++      ROUND(G, a, b, c, d, in[0] + K2,  3);
++      ROUND(G, d, a, b, c, in[2] + K2,  5);
++      ROUND(G, c, d, a, b, in[4] + K2,  9);
++      ROUND(G, b, c, d, a, in[6] + K2, 13);
++
++      /* Round 3 */
++      ROUND(H, a, b, c, d, in[3] + K3,  3);
++      ROUND(H, d, a, b, c, in[7] + K3,  9);
++      ROUND(H, c, d, a, b, in[2] + K3, 11);
++      ROUND(H, b, c, d, a, in[6] + K3, 15);
++      ROUND(H, a, b, c, d, in[1] + K3,  3);
++      ROUND(H, d, a, b, c, in[5] + K3,  9);
++      ROUND(H, c, d, a, b, in[0] + K3, 11);
++      ROUND(H, b, c, d, a, in[4] + K3, 15);
++
++      buf[0] += a;
++      buf[1] += b;
++      buf[2] += c;
++      buf[3] += d;
++}
++
++#undef ROUND
++#undef F
++#undef G
++#undef H
++#undef K1
++#undef K2
++#undef K3
++
++/* The old legacy hash */
++static ext2_dirhash_t dx_hack_hash (const char *name, int len)
++{
++      __u32 hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9;
++      while (len--) {
++              __u32 hash = hash1 + (hash0 ^ (*name++ * 7152373));
++              
++              if (hash & 0x80000000) hash -= 0x7fffffff;
++              hash1 = hash0;
++              hash0 = hash;
++      }
++      return (hash0 << 1);
++}
++
++static void str2hashbuf(const char *msg, int len, __u32 *buf, int num)
++{
++      __u32   pad, val;
++      int     i;
++
++      pad = (__u32)len | ((__u32)len << 8);
++      pad |= pad << 16;
++
++      val = pad;
++      if (len > num*4)
++              len = num * 4;
++      for (i=0; i < len; i++) {
++              if ((i % 4) == 0)
++                      val = pad;
++              val = msg[i] + (val << 8);
++              if ((i % 4) == 3) {
++                      *buf++ = val;
++                      val = pad;
++                      num--;
++              }
++      }
++      if (--num >= 0)
++              *buf++ = val;
++      while (--num >= 0)
++              *buf++ = pad;
++}
++
++/*
++ * Returns the hash of a filename.  If len is 0 and name is NULL, then
++ * this function can be used to test whether or not a hash version is
++ * supported.
++ * 
++ * The seed is an 4 longword (32 bits) "secret" which can be used to
++ * uniquify a hash.  If the seed is all zero's, then some default seed
++ * may be used.
++ * 
++ * A particular hash version specifies whether or not the seed is
++ * represented, and whether or not the returned hash is 32 bits or 64
++ * bits.  32 bit hashes will return 0 for the minor hash.
++ */
++errcode_t ext2fs_dirhash(int version, const char *name, int len,
++                       const __u32 *seed,
++                       ext2_dirhash_t *ret_hash,
++                       ext2_dirhash_t *ret_minor_hash)
++{
++      __u32   hash;
++      __u32   minor_hash = 0;
++      const char      *p;
++      int             i;
++      __u32           in[8], buf[4];
++
++      /* Initialize the default seed for the hash checksum functions */
++      buf[0] = 0x67452301;
++      buf[1] = 0xefcdab89;
++      buf[2] = 0x98badcfe;
++      buf[3] = 0x10325476;
++
++      /* Check to see if the seed is all zero's */
++      if (seed) {
++              for (i=0; i < 4; i++) {
++                      if (seed[i])
++                              break;
++              }
++              if (i < 4)
++                      memcpy(buf, seed, sizeof(buf));
++      }
++              
++      switch (version) {
++      case EXT2_HASH_LEGACY:
++              hash = dx_hack_hash(name, len);
++              break;
++      case EXT2_HASH_HALF_MD4:
++              p = name;
++              while (len > 0) {
++                      str2hashbuf(p, len, in, 8);
++                      halfMD4Transform(buf, in);
++                      len -= 32;
++                      p += 32;
++              }
++              minor_hash = buf[2];
++              hash = buf[1];
++              break;
++      case EXT2_HASH_TEA:
++              p = name;
++              while (len > 0) {
++                      str2hashbuf(p, len, in, 4);
++                      TEA_transform(buf, in);
++                      len -= 16;
++                      p += 16;
++              }
++              hash = buf[0];
++              minor_hash = buf[1];
++              break;
++      default:
++              *ret_hash = 0;
++              return EXT2_ET_DIRHASH_UNSUPP;
++      }
++      *ret_hash = hash & ~1;
++      if (ret_minor_hash)
++              *ret_minor_hash = minor_hash;
++      return 0;
++}
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/dosio.c busybox/e2fsprogs/ext2fs/dosio.c
+--- busybox-1.00/e2fsprogs/ext2fs/dosio.c      1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/dosio.c   2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,456 @@
++/*
++ * dosio.c -- Disk I/O module for the ext2fs/DOS library.
++ *
++ * Copyright (c) 1997 by Theodore Ts'o.
++ * 
++ * Copyright (c) 1997 Mark Habersack
++ * This file may be distributed under the terms of the GNU Public License.
++ *
++ */
++
++#include <stdio.h>
++#include <bios.h>
++#include <string.h>
++#include <ctype.h>
++#include <io.h>
++#ifdef HAVE_ERRNO_H
++#include <errno.h>
++#endif
++
++#include <ext2fs/ext2_types.h>
++#include "utils.h"
++#include "dosio.h"
++#include "et/com_err.h"
++#include "ext2_err.h"
++#include "ext2fs/io.h"
++
++/*
++ * Some helper macros
++ */
++#define LINUX_EXT2FS       0x83
++#define LINUX_SWAP         0x82
++#define WRITE_ERR(_msg_) write(2, _msg_, strlen(_msg_))
++#define WRITE_ERR_S(_msg_) write(2, _msg_, sizeof(_msg_))
++
++/*
++ * Exported variables
++ */
++unsigned long        _dio_error;
++unsigned long        _dio_hw_error;
++
++/*
++ * Array of all opened partitions
++ */
++static PARTITION        **partitions = NULL;
++static unsigned short   npart = 0; /* Number of mapped partitions */
++static PARTITION        *active = NULL;
++
++/*
++ * I/O Manager routine prototypes
++ */
++static errcode_t dos_open(const char *dev, int flags, io_channel *channel);
++static errcode_t dos_close(io_channel channel);
++static errcode_t dos_set_blksize(io_channel channel, int blksize);
++static errcode_t dos_read_blk(io_channel channel, unsigned long block,
++                                             int count, void *buf);
++static errcode_t dos_write_blk(io_channel channel, unsigned long block,
++                               int count, const void *buf);
++static errcode_t dos_flush(io_channel channel);
++
++static struct struct_io_manager struct_dos_manager = {
++        EXT2_ET_MAGIC_IO_MANAGER,
++        "DOS I/O Manager",
++        dos_open,
++        dos_close,
++        dos_set_blksize,
++        dos_read_blk,
++        dos_write_blk,
++        dos_flush
++};
++io_manager dos_io_manager = &struct_dos_manager;
++
++/*
++ * Macro taken from unix_io.c
++ */
++/*
++ * For checking structure magic numbers...
++ */
++
++#define EXT2_CHECK_MAGIC(struct, code) \
++          if ((struct)->magic != (code)) return (code)
++
++/*
++ * Calculates a CHS address of a sector from its LBA
++ * offset for the given partition.
++ */
++static void lba2chs(unsigned long lba_addr, CHS *chs, PARTITION *part)
++{
++  unsigned long      abss;
++
++  chs->offset = lba_addr & 0x000001FF;
++  abss = (lba_addr >> 9) + part->start;
++  chs->cyl    = abss / (part->sects * part->heads);
++  chs->head   = (abss / part->sects) % part->heads;
++  chs->sector = (abss % part->sects) + 1;
++}
++
++#ifdef __TURBOC__
++#pragma argsused
++#endif
++/*
++ * Scans the passed partition table looking for *pno partition
++ * that has LINUX_EXT2FS type.
++ *
++ * TODO:
++ * For partition numbers >5 Linux uses DOS extended partitions -
++ * dive into them an return an appropriate entry. Also dive into
++ * extended partitions when scanning for a first Linux/ext2fs.
++ */
++static PTABLE_ENTRY *scan_partition_table(PTABLE_ENTRY *pentry,
++                                          unsigned short phys,
++                                          unsigned char *pno)
++{
++  unsigned        i;
++
++  if(*pno != 0xFF && *pno >= 5)
++     return NULL; /* We don't support extended partitions for now */
++
++  if(*pno != 0xFF)
++  {
++    if(pentry[*pno].type == LINUX_EXT2FS)
++      return &pentry[*pno];
++    else
++    {
++      if(!pentry[*pno].type)
++        *pno = 0xFE;
++      else if(pentry[*pno].type == LINUX_SWAP)
++        *pno = 0xFD;
++      return NULL;
++    }
++  }
++
++  for(i = 0; i < 4; i++)
++    if(pentry[i].type == LINUX_EXT2FS)
++    {
++      *pno = i;
++      return &pentry[i];
++    }
++
++  return NULL;
++}
++
++/*
++ * Allocate libext2fs structures associated with I/O manager
++ */
++static io_channel alloc_io_channel(PARTITION *part)
++{
++  io_channel     ioch;
++
++  ioch = (io_channel)malloc(sizeof(struct struct_io_channel));
++  if (!ioch)
++        return NULL;
++  memset(ioch, 0, sizeof(struct struct_io_channel));
++  ioch->magic = EXT2_ET_MAGIC_IO_CHANNEL;
++  ioch->manager = dos_io_manager;
++  ioch->name = (char *)malloc(strlen(part->dev)+1);
++  if (!ioch->name) {
++        free(ioch);
++        return NULL;
++  }
++  strcpy(ioch->name, part->dev);
++  ioch->private_data = part;
++  ioch->block_size = 1024; /* The smallest ext2fs block size */
++  ioch->read_error = 0;
++  ioch->write_error = 0;
++
++  return ioch;
++}
++
++#ifdef __TURBOC__
++#pragma argsused
++#endif
++/*
++ * Open the 'name' partition, initialize all information structures
++ * we need to keep and create libext2fs I/O manager.
++ */
++static errcode_t dos_open(const char *dev, int flags, io_channel *channel)
++{
++  unsigned char  *tmp, sec[512];
++  PARTITION      *part;
++  PTABLE_ENTRY   *pent;
++  PARTITION        **newparts;
++  
++  if(!dev)
++  {
++    _dio_error = ERR_BADDEV;
++    return EXT2_ET_BAD_DEVICE_NAME;
++  }
++
++  /*
++   * First check whether the dev name is OK
++   */
++  tmp = (unsigned char*)strrchr(dev, '/');
++  if(!tmp)
++  {
++    _dio_error = ERR_BADDEV;
++    return EXT2_ET_BAD_DEVICE_NAME;
++  }
++  *tmp = 0;
++  if(strcmp(dev, "/dev"))
++  {
++    _dio_error = ERR_BADDEV;
++    return EXT2_ET_BAD_DEVICE_NAME;
++  }
++  *tmp++ = '/';
++
++  /*
++   * Check whether the partition data is already in cache
++   */
++
++  part = (PARTITION*)malloc(sizeof(PARTITION));
++  if (!part)
++        return ENOMEM;
++  {
++    int   i = 0;
++
++    for(;i < npart; i++)
++      if(!strcmp(partitions[i]->dev, dev))
++      {
++        /* Found it! Make it the active one */
++        active = partitions[i];
++        *channel = alloc_io_channel(active);
++      if (!*channel)
++              return ENOMEM;
++        return 0;
++      }
++  }
++
++  /*
++   * Drive number & optionally partn number
++   */
++  switch(tmp[0])
++  {
++    case 'h':
++    case 's':
++      part->phys = 0x80;
++      part->phys += toupper(tmp[2]) - 'A';
++      /*
++       * Do we have the partition number?
++       */
++      if(tmp[3])
++        part->pno = isdigit((int)tmp[3]) ? tmp[3] - '0' - 1: 0;
++      else
++        part->pno = 0xFF;
++      break;
++
++    case 'f':
++      if(tmp[2])
++        part->phys = isdigit((int)tmp[2]) ? tmp[2] - '0' : 0;
++      else
++        part->phys = 0x00; /* We'll assume /dev/fd0 */
++      break;
++
++    default:
++      _dio_error = ERR_BADDEV;
++      return ENODEV;
++  }
++
++  if(part->phys < 0x80)
++  {
++     /* We don't support floppies for now */
++     _dio_error = ERR_NOTSUPP;
++     return EINVAL;
++  }
++
++  part->dev = strdup(dev);
++
++  /*
++   * Get drive's geometry
++   */
++  _dio_hw_error = biosdisk(DISK_GET_GEOMETRY,
++                           part->phys,
++                           0, /* head */
++                           0, /* cylinder */
++                           1, /* sector */
++                           1, /* just one sector */
++                           sec);
++
++  if(!HW_OK())
++  {
++    _dio_error = ERR_HARDWARE;
++    if (part)
++          free(part);
++    return EFAULT;
++  }
++
++  /*
++   * Calculate the geometry
++   */
++  part->cyls  = (unsigned short)(((sec[0] >> 6) << 8) + sec[1] + 1);
++  part->heads = sec[3] + 1;
++  part->sects = sec[0] & 0x3F;
++
++  /*
++   * Now that we know all we need, let's look for the partition
++   */
++  _dio_hw_error = biosdisk(DISK_READ, part->phys, 0, 0, 1, 1, sec);
++
++  if(!HW_OK())
++  {
++    _dio_error = ERR_HARDWARE;
++    if (part)
++          free(part);
++    return EFAULT;
++  }
++
++  pent = (PTABLE_ENTRY*)&sec[0x1BE];
++  pent = scan_partition_table(pent, part->phys, &part->pno);
++
++  if(!pent)
++  {
++    _dio_error = part->pno == 0xFE ? ERR_EMPTYPART :
++                 part->pno == 0xFD ? ERR_LINUXSWAP : ERR_NOTEXT2FS;
++    if (part)
++          free(part);
++    return ENODEV;
++  }
++
++  /*
++   * Calculate the remaining figures
++   */
++  {
++    unsigned long    fsec, fhead, fcyl;
++
++    fsec = (unsigned long)(pent->start_sec & 0x3F);
++    fhead = (unsigned long)pent->start_head;
++    fcyl = ((pent->start_sec >> 6) << 8) + pent->start_cyl;
++    part->start = fsec + fhead * part->sects + fcyl *
++                  (part->heads * part->sects) - 1;
++    part->len = pent->size;
++  }
++
++  /*
++   * Add the partition to the table
++   */
++  newparts = (PARTITION**)realloc(partitions, sizeof(PARTITION) * npart);
++  if (!newparts) {
++        free(part);
++        return ENOMEM;
++  }
++  partitions = newparts;
++  partitions[npart++] = active = part;
++
++  /*
++   * Now alloc all libe2fs structures
++   */
++  *channel = alloc_io_channel(active);
++  if (!*channel)
++        return ENOMEM;
++
++  return 0;
++}
++
++static errcode_t dos_close(io_channel channel)
++{
++      if (channel->name)
++              free(channel->name);
++      if (channel)
++              free(channel);
++
++      return 0;
++}
++
++static errcode_t dos_set_blksize(io_channel channel, int blksize)
++{
++  channel->block_size = blksize;
++
++  return 0;
++}
++
++static errcode_t dos_read_blk(io_channel channel, unsigned long block,
++                                             int count, void *buf)
++{
++  PARTITION     *part;
++  size_t        size;
++  ext2_loff_t   loc;
++  CHS           chs;
++
++  EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
++  part = (PARTITION*)channel->private_data;
++
++  size = (size_t)((count < 0) ? -count : count * channel->block_size);
++  loc = (ext2_loff_t) block * channel->block_size;
++
++  lba2chs(loc, &chs, part);
++  /*
++   * Potential bug here:
++   *   If DJGPP is used then reads of >18 sectors will fail!
++   *   Have to rewrite biosdisk.
++   */
++  _dio_hw_error = biosdisk(DISK_READ,
++                           part->phys,
++                           chs.head,
++                           chs.cyl,
++                           chs.sector,
++                           size < 512 ? 1 : size/512,
++                           buf);
++
++  if(!HW_OK())
++  {
++    _dio_error = ERR_HARDWARE;
++    return EFAULT;
++  }
++
++  return 0;
++}
++
++static errcode_t dos_write_blk(io_channel channel, unsigned long block,
++                               int count, const void *buf)
++{
++  PARTITION     *part;
++  size_t        size;
++  ext2_loff_t   loc;
++  CHS           chs;
++
++  EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
++  part = (PARTITION*)channel->private_data;
++
++  if(count == 1)
++    size = (size_t)channel->block_size;
++  else
++  {
++    if (count < 0)
++      size = (size_t)-count;
++    else
++      size = (size_t)(count * channel->block_size);
++  }
++
++  loc = (ext2_loff_t)block * channel->block_size;
++  lba2chs(loc, &chs, part);
++  _dio_hw_error = biosdisk(DISK_WRITE,
++                           part->phys,
++                           chs.head,
++                           chs.cyl,
++                           chs.sector,
++                           size < 512 ? 1 : size/512,
++                           (void*)buf);
++
++  if(!HW_OK())
++  {
++    _dio_error = ERR_HARDWARE;
++    return EFAULT;
++  }
++
++  return 0;
++}
++
++#ifdef __TURBOC__
++#pragma argsused
++#endif
++static errcode_t dos_flush(io_channel channel)
++{
++  /*
++   * No buffers, no flush...
++   */
++  return 0;
++}
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/dosio.h busybox/e2fsprogs/ext2fs/dosio.h
+--- busybox-1.00/e2fsprogs/ext2fs/dosio.h      1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/dosio.h   2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,153 @@
++/*
++ * v1.0
++ *
++ * Disk I/O include file for the ext2fs/DOS library.
++ *
++ * Copyright (c) 1997 Mark Habersack
++ * This file may be distributed under the terms of the GNU Public License.
++ *
++ */
++#ifndef __diskio_h
++#define __diskio_h
++#ifdef __TURBOC__
++#ifndef __LARGE__
++# error "ext2fs/DOS library requires LARGE model!"
++#endif
++#endif
++
++#ifdef __TURBOC__
++#include "msdos.h"
++#endif
++
++/*
++ * A helper structure used in LBA => CHS conversion
++ */
++typedef struct
++{
++  unsigned short       cyl;     /* Cylinder (or track) */
++  unsigned short       head;
++  unsigned short       sector;
++  unsigned short       offset;  /* Offset of byte within the sector */
++} CHS;
++
++/*
++ * All partition data we need is here
++ */
++typedef struct
++{
++  char                 *dev;  /* _Linux_ device name (like "/dev/hda1") */
++  unsigned char        phys;  /* Physical DOS drive number */
++  unsigned long        start; /* LBA address of partition start */
++  unsigned long        len;   /* length of partition in sectors */
++  unsigned char        pno;   /* Partition number (read from *dev) */
++
++  /* This partition's drive geometry */
++  unsigned short       cyls;
++  unsigned short       heads;
++  unsigned short       sects;
++} PARTITION;
++
++/*
++ * PC partition table entry format
++ */
++#ifdef __DJGPP__
++#pragma pack(1)
++#endif
++typedef struct
++{
++  unsigned char        active;
++  unsigned char        start_head;
++  unsigned char        start_sec;
++  unsigned char        start_cyl;
++  unsigned char        type;
++  unsigned char        end_head;
++  unsigned char        end_sec;
++  unsigned char        end_cyl;
++  unsigned long        first_sec_rel;
++  unsigned long        size;
++} PTABLE_ENTRY;
++#ifdef __DJGPP__
++#pragma pack()
++#endif
++
++/*
++ * INT 0x13 operation codes
++ */
++#define DISK_READ          0x02
++#define DISK_WRITE         0x03
++#define DISK_GET_GEOMETRY  0x08
++#define DISK_READY         0x10
++
++/*
++ * Errors to put in _dio_error
++ */
++#define ERR_BADDEV         0x00000001L
++#define ERR_HARDWARE       0x00000002L
++#define ERR_NOTSUPP        0x00000003L
++#define ERR_NOTEXT2FS      0x00000004L
++#define ERR_EMPTYPART      0x00000005L
++#define ERR_LINUXSWAP      0x00000006L
++
++/*
++ * Functions in diskio.c
++ */
++
++/*
++ * Variable contains last module's error
++ */
++extern unsigned long        _dio_error;
++
++/*
++ * This one contains last hardware error (if _dio_error == ERR_HARDWARE)
++ */
++extern unsigned long        _dio_hw_error;
++
++/*
++ * Macros to check for disk hardware errors
++ */
++#define HW_OK()             ((unsigned char)_dio_hw_error == 0x00)
++#define HW_BAD_CMD()        ((unsigned char)_dio_hw_error == 0x01)
++#define HW_NO_ADDR_MARK()   ((unsigned char)_dio_hw_error == 0x02)
++#define HW_WRITE_PROT()     ((unsigned char)_dio_hw_error == 0x03)
++#define HW_NO_SECTOR()      ((unsigned char)_dio_hw_error == 0x04)
++#define HW_RESET_FAIL()     ((unsigned char)_dio_hw_error == 0x05)
++#define HW_DISK_CHANGED()   ((unsigned char)_dio_hw_error == 0x06)
++#define HW_DRIVE_FAIL()     ((unsigned char)_dio_hw_error == 0x07)
++#define HW_DMA_OVERRUN()    ((unsigned char)_dio_hw_error == 0x08)
++#define HW_DMA_BOUNDARY()   ((unsigned char)_dio_hw_error == 0x09)
++#define HW_BAD_SECTOR()     ((unsigned char)_dio_hw_error == 0x0A)
++#define HW_BAD_TRACK()      ((unsigned char)_dio_hw_error == 0x0B)
++#define HW_UNSUPP_TRACK()   ((unsigned char)_dio_hw_error == 0x0C)
++#define HW_BAD_CRC_ECC()    ((unsigned char)_dio_hw_error == 0x10)
++#define HW_CRC_ECC_CORR()   ((unsigned char)_dio_hw_error == 0x11)
++#define HW_CONTR_FAIL()     ((unsigned char)_dio_hw_error == 0x20)
++#define HW_SEEK_FAIL()      ((unsigned char)_dio_hw_error == 0x40)
++#define HW_ATTACH_FAIL()    ((unsigned char)_dio_hw_error == 0x80)
++#define HW_DRIVE_NREADY()   ((unsigned char)_dio_hw_error == 0xAA)
++#define HW_UNDEF_ERROR()    ((unsigned char)_dio_hw_error == 0xBB)
++#define HW_WRITE_FAULT()    ((unsigned char)_dio_hw_error == 0xCC)
++#define HW_STATUS_ERROR()   ((unsigned char)_dio_hw_error == 0xE0)
++#define HW_SENSE_FAIL()     ((unsigned char)_dio_hw_error == 0xFF)
++
++
++/*
++ * Open the specified partition.
++ * String 'dev' must have a format:
++ *
++ *  /dev/{sd|hd|fd}[X]
++ *
++ * where,
++ *
++ *  only one of the option in curly braces can be used and X is an optional
++ *  partition number for the given device. If X is not specified, function
++ *  scans the drive's partition table in search for the first Linux ext2fs
++ *  partition (signature 0x83). Along the way it dives into every extended
++ *  partition encountered.
++ *  Scan ends if either (a) there are no more used partition entries, or
++ *  (b) there is no Xth partition.
++ *
++ * Routine returns 0 on success and !=0 otherwise.
++ */
++int open_partition(char *dev);
++
++#endif /* __diskio_h */
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/dupfs.c busybox/e2fsprogs/ext2fs/dupfs.c
+--- busybox-1.00/e2fsprogs/ext2fs/dupfs.c      1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/dupfs.c   2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,96 @@
++/*
++ * dupfs.c --- duplicate a ext2 filesystem handle
++ * 
++ * Copyright (C) 1997, 1998, 2001, 2003, 2005 by Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <time.h>
++#include <string.h>
++
++#include "ext2_fs.h"
++#include "ext2fsP.h"
++
++errcode_t ext2fs_dup_handle(ext2_filsys src, ext2_filsys *dest)
++{
++      ext2_filsys     fs;
++      errcode_t       retval;
++
++      EXT2_CHECK_MAGIC(src, EXT2_ET_MAGIC_EXT2FS_FILSYS);
++      
++      retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &fs);
++      if (retval)
++              return retval;
++
++      *fs = *src;
++      fs->device_name = 0;
++      fs->super = 0;
++      fs->orig_super = 0;
++      fs->group_desc = 0;
++      fs->inode_map = 0;
++      fs->block_map = 0;
++      fs->badblocks = 0;
++      fs->dblist = 0;
++
++      io_channel_bumpcount(fs->io);
++      if (fs->icache)
++              fs->icache->refcount++;
++
++      retval = ext2fs_get_mem(strlen(src->device_name)+1, &fs->device_name);
++      if (retval)
++              goto errout;
++      strcpy(fs->device_name, src->device_name);
++
++      retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->super);
++      if (retval)
++              goto errout;
++      memcpy(fs->super, src->super, SUPERBLOCK_SIZE);
++
++      retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->orig_super);
++      if (retval)
++              goto errout;
++      memcpy(fs->orig_super, src->orig_super, SUPERBLOCK_SIZE);
++
++      retval = ext2fs_get_mem((size_t) fs->desc_blocks * fs->blocksize,
++                              &fs->group_desc);
++      if (retval)
++              goto errout;
++      memcpy(fs->group_desc, src->group_desc,
++             (size_t) fs->desc_blocks * fs->blocksize);
++
++      if (src->inode_map) {
++              retval = ext2fs_copy_bitmap(src->inode_map, &fs->inode_map);
++              if (retval)
++                      goto errout;
++      }
++      if (src->block_map) {
++              retval = ext2fs_copy_bitmap(src->block_map, &fs->block_map);
++              if (retval)
++                      goto errout;
++      }
++      if (src->badblocks) {
++              retval = ext2fs_badblocks_copy(src->badblocks, &fs->badblocks);
++              if (retval)
++                      goto errout;
++      }
++      if (src->dblist) {
++              retval = ext2fs_copy_dblist(src->dblist, &fs->dblist);
++              if (retval)
++                      goto errout;
++      }
++      *dest = fs;
++      return 0;
++errout:
++      ext2fs_free(fs);
++      return retval;
++      
++}
++
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/e2image.h busybox/e2fsprogs/ext2fs/e2image.h
+--- busybox-1.00/e2fsprogs/ext2fs/e2image.h    1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/e2image.h 2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,51 @@
++/*
++ * e2image.h --- header file describing the ext2 image format
++ * 
++ * Copyright (C) 2000 Theodore Ts'o.
++ *
++ * Note: this uses the POSIX IO interfaces, unlike most of the other
++ * functions in this library.  So sue me.  
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++
++struct ext2_image_hdr {
++      __u32   magic_number;   /* This must be EXT2_ET_MAGIC_E2IMAGE */
++      char    magic_descriptor[16]; /* "Ext2 Image 1.0", w/ null padding */
++      char    fs_hostname[64];/* Hostname of machine of image */
++      char    fs_netaddr[32]; /* Network address */
++      __u32   fs_netaddr_type;/* 0 = IPV4, 1 = IPV6, etc. */
++      __u32   fs_device;      /* Device number of image */
++      char    fs_device_name[64]; /* Device name */
++      char    fs_uuid[16];    /* UUID of filesystem */
++      __u32   fs_blocksize;   /* Block size of the filesystem */
++      __u32   fs_reserved[8];
++      
++      __u32   image_device;   /* Device number of image file */
++      __u32   image_inode;    /* Inode number of image file */
++      __u32   image_time;     /* Time of image creation */
++      __u32   image_reserved[8];
++
++      __u32   offset_super;   /* Byte offset of the sb and descriptors */
++      __u32   offset_inode;   /* Byte offset of the inode table  */
++      __u32   offset_inodemap; /* Byte offset of the inode bitmaps */
++      __u32   offset_blockmap; /* Byte offset of the inode bitmaps */
++      __u32   offset_reserved[8];
++};
++
++      
++      
++      
++      
++      
++      
++      
++      
++      
++      
++      
++      
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/expanddir.c busybox/e2fsprogs/ext2fs/expanddir.c
+--- busybox-1.00/e2fsprogs/ext2fs/expanddir.c  1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/expanddir.c       2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,126 @@
++/*
++ * expand.c --- expand an ext2fs directory
++ * 
++ * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999  Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++struct expand_dir_struct {
++      int             done;
++      int             newblocks;
++      errcode_t       err;
++};
++
++static int expand_dir_proc(ext2_filsys        fs,
++                         blk_t        *blocknr,
++                         e2_blkcnt_t  blockcnt,
++                         blk_t        ref_block EXT2FS_ATTR((unused)),
++                         int          ref_offset EXT2FS_ATTR((unused)),
++                         void         *priv_data)
++{
++      struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data;
++      blk_t   new_blk;
++      static blk_t    last_blk = 0;
++      char            *block;
++      errcode_t       retval;
++      
++      if (*blocknr) {
++              last_blk = *blocknr;
++              return 0;
++      }
++      retval = ext2fs_new_block(fs, last_blk, 0, &new_blk);
++      if (retval) {
++              es->err = retval;
++              return BLOCK_ABORT;
++      }
++      if (blockcnt > 0) {
++              retval = ext2fs_new_dir_block(fs, 0, 0, &block);
++              if (retval) {
++                      es->err = retval;
++                      return BLOCK_ABORT;
++              }
++              es->done = 1;
++              retval = ext2fs_write_dir_block(fs, new_blk, block);
++      } else {
++              retval = ext2fs_get_mem(fs->blocksize, &block);
++              if (retval) {
++                      es->err = retval;
++                      return BLOCK_ABORT;
++              }
++              memset(block, 0, fs->blocksize);
++              retval = io_channel_write_blk(fs->io, new_blk, 1, block);
++      }       
++      if (retval) {
++              es->err = retval;
++              return BLOCK_ABORT;
++      }
++      ext2fs_free_mem(&block);
++      *blocknr = new_blk;
++      ext2fs_block_alloc_stats(fs, new_blk, +1);
++      es->newblocks++;
++
++      if (es->done)
++              return (BLOCK_CHANGED | BLOCK_ABORT);
++      else
++              return BLOCK_CHANGED;
++}
++
++errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir)
++{
++      errcode_t       retval;
++      struct expand_dir_struct es;
++      struct ext2_inode       inode;
++      
++      EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
++
++      if (!(fs->flags & EXT2_FLAG_RW))
++              return EXT2_ET_RO_FILSYS;
++
++      if (!fs->block_map)
++              return EXT2_ET_NO_BLOCK_BITMAP;
++
++      retval = ext2fs_check_directory(fs, dir);
++      if (retval)
++              return retval;
++      
++      es.done = 0;
++      es.err = 0;
++      es.newblocks = 0;
++      
++      retval = ext2fs_block_iterate2(fs, dir, BLOCK_FLAG_APPEND,
++                                     0, expand_dir_proc, &es);
++
++      if (es.err)
++              return es.err;
++      if (!es.done)
++              return EXT2_ET_EXPAND_DIR_ERR;
++
++      /*
++       * Update the size and block count fields in the inode.
++       */
++      retval = ext2fs_read_inode(fs, dir, &inode);
++      if (retval)
++              return retval;
++      
++      inode.i_size += fs->blocksize;
++      inode.i_blocks += (fs->blocksize / 512) * es.newblocks;
++
++      retval = ext2fs_write_inode(fs, dir, &inode);
++      if (retval)
++              return retval;
++
++      return 0;
++}
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/ext2_err.h busybox/e2fsprogs/ext2fs/ext2_err.h
+--- busybox-1.00/e2fsprogs/ext2fs/ext2_err.h   1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/ext2_err.h        2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,117 @@
++/*
++ * ext2_err.h:
++ * This file is automatically generated; please do not edit it.
++ */
++
++#include <et/com_err.h>
++
++#define EXT2_ET_BASE                             (2133571328L)
++#define EXT2_ET_MAGIC_EXT2FS_FILSYS              (2133571329L)
++#define EXT2_ET_MAGIC_BADBLOCKS_LIST             (2133571330L)
++#define EXT2_ET_MAGIC_BADBLOCKS_ITERATE          (2133571331L)
++#define EXT2_ET_MAGIC_INODE_SCAN                 (2133571332L)
++#define EXT2_ET_MAGIC_IO_CHANNEL                 (2133571333L)
++#define EXT2_ET_MAGIC_UNIX_IO_CHANNEL            (2133571334L)
++#define EXT2_ET_MAGIC_IO_MANAGER                 (2133571335L)
++#define EXT2_ET_MAGIC_BLOCK_BITMAP               (2133571336L)
++#define EXT2_ET_MAGIC_INODE_BITMAP               (2133571337L)
++#define EXT2_ET_MAGIC_GENERIC_BITMAP             (2133571338L)
++#define EXT2_ET_MAGIC_TEST_IO_CHANNEL            (2133571339L)
++#define EXT2_ET_MAGIC_DBLIST                     (2133571340L)
++#define EXT2_ET_MAGIC_ICOUNT                     (2133571341L)
++#define EXT2_ET_MAGIC_PQ_IO_CHANNEL              (2133571342L)
++#define EXT2_ET_MAGIC_EXT2_FILE                  (2133571343L)
++#define EXT2_ET_MAGIC_E2IMAGE                    (2133571344L)
++#define EXT2_ET_MAGIC_INODE_IO_CHANNEL           (2133571345L)
++#define EXT2_ET_MAGIC_RESERVED_9                 (2133571346L)
++#define EXT2_ET_BAD_MAGIC                        (2133571347L)
++#define EXT2_ET_REV_TOO_HIGH                     (2133571348L)
++#define EXT2_ET_RO_FILSYS                        (2133571349L)
++#define EXT2_ET_GDESC_READ                       (2133571350L)
++#define EXT2_ET_GDESC_WRITE                      (2133571351L)
++#define EXT2_ET_GDESC_BAD_BLOCK_MAP              (2133571352L)
++#define EXT2_ET_GDESC_BAD_INODE_MAP              (2133571353L)
++#define EXT2_ET_GDESC_BAD_INODE_TABLE            (2133571354L)
++#define EXT2_ET_INODE_BITMAP_WRITE               (2133571355L)
++#define EXT2_ET_INODE_BITMAP_READ                (2133571356L)
++#define EXT2_ET_BLOCK_BITMAP_WRITE               (2133571357L)
++#define EXT2_ET_BLOCK_BITMAP_READ                (2133571358L)
++#define EXT2_ET_INODE_TABLE_WRITE                (2133571359L)
++#define EXT2_ET_INODE_TABLE_READ                 (2133571360L)
++#define EXT2_ET_NEXT_INODE_READ                  (2133571361L)
++#define EXT2_ET_UNEXPECTED_BLOCK_SIZE            (2133571362L)
++#define EXT2_ET_DIR_CORRUPTED                    (2133571363L)
++#define EXT2_ET_SHORT_READ                       (2133571364L)
++#define EXT2_ET_SHORT_WRITE                      (2133571365L)
++#define EXT2_ET_DIR_NO_SPACE                     (2133571366L)
++#define EXT2_ET_NO_INODE_BITMAP                  (2133571367L)
++#define EXT2_ET_NO_BLOCK_BITMAP                  (2133571368L)
++#define EXT2_ET_BAD_INODE_NUM                    (2133571369L)
++#define EXT2_ET_BAD_BLOCK_NUM                    (2133571370L)
++#define EXT2_ET_EXPAND_DIR_ERR                   (2133571371L)
++#define EXT2_ET_TOOSMALL                         (2133571372L)
++#define EXT2_ET_BAD_BLOCK_MARK                   (2133571373L)
++#define EXT2_ET_BAD_BLOCK_UNMARK                 (2133571374L)
++#define EXT2_ET_BAD_BLOCK_TEST                   (2133571375L)
++#define EXT2_ET_BAD_INODE_MARK                   (2133571376L)
++#define EXT2_ET_BAD_INODE_UNMARK                 (2133571377L)
++#define EXT2_ET_BAD_INODE_TEST                   (2133571378L)
++#define EXT2_ET_FUDGE_BLOCK_BITMAP_END           (2133571379L)
++#define EXT2_ET_FUDGE_INODE_BITMAP_END           (2133571380L)
++#define EXT2_ET_BAD_IND_BLOCK                    (2133571381L)
++#define EXT2_ET_BAD_DIND_BLOCK                   (2133571382L)
++#define EXT2_ET_BAD_TIND_BLOCK                   (2133571383L)
++#define EXT2_ET_NEQ_BLOCK_BITMAP                 (2133571384L)
++#define EXT2_ET_NEQ_INODE_BITMAP                 (2133571385L)
++#define EXT2_ET_BAD_DEVICE_NAME                  (2133571386L)
++#define EXT2_ET_MISSING_INODE_TABLE              (2133571387L)
++#define EXT2_ET_CORRUPT_SUPERBLOCK               (2133571388L)
++#define EXT2_ET_BAD_GENERIC_MARK                 (2133571389L)
++#define EXT2_ET_BAD_GENERIC_UNMARK               (2133571390L)
++#define EXT2_ET_BAD_GENERIC_TEST                 (2133571391L)
++#define EXT2_ET_SYMLINK_LOOP                     (2133571392L)
++#define EXT2_ET_CALLBACK_NOTHANDLED              (2133571393L)
++#define EXT2_ET_BAD_BLOCK_IN_INODE_TABLE         (2133571394L)
++#define EXT2_ET_UNSUPP_FEATURE                   (2133571395L)
++#define EXT2_ET_RO_UNSUPP_FEATURE                (2133571396L)
++#define EXT2_ET_LLSEEK_FAILED                    (2133571397L)
++#define EXT2_ET_NO_MEMORY                        (2133571398L)
++#define EXT2_ET_INVALID_ARGUMENT                 (2133571399L)
++#define EXT2_ET_BLOCK_ALLOC_FAIL                 (2133571400L)
++#define EXT2_ET_INODE_ALLOC_FAIL                 (2133571401L)
++#define EXT2_ET_NO_DIRECTORY                     (2133571402L)
++#define EXT2_ET_TOO_MANY_REFS                    (2133571403L)
++#define EXT2_ET_FILE_NOT_FOUND                   (2133571404L)
++#define EXT2_ET_FILE_RO                          (2133571405L)
++#define EXT2_ET_DB_NOT_FOUND                     (2133571406L)
++#define EXT2_ET_DIR_EXISTS                       (2133571407L)
++#define EXT2_ET_UNIMPLEMENTED                    (2133571408L)
++#define EXT2_ET_CANCEL_REQUESTED                 (2133571409L)
++#define EXT2_ET_FILE_TOO_BIG                     (2133571410L)
++#define EXT2_ET_JOURNAL_NOT_BLOCK                (2133571411L)
++#define EXT2_ET_NO_JOURNAL_SB                    (2133571412L)
++#define EXT2_ET_JOURNAL_TOO_SMALL                (2133571413L)
++#define EXT2_ET_JOURNAL_UNSUPP_VERSION           (2133571414L)
++#define EXT2_ET_LOAD_EXT_JOURNAL                 (2133571415L)
++#define EXT2_ET_NO_JOURNAL                       (2133571416L)
++#define EXT2_ET_DIRHASH_UNSUPP                   (2133571417L)
++#define EXT2_ET_BAD_EA_BLOCK_NUM                 (2133571418L)
++#define EXT2_ET_TOO_MANY_INODES                  (2133571419L)
++#define EXT2_ET_NOT_IMAGE_FILE                   (2133571420L)
++#define EXT2_ET_RES_GDT_BLOCKS                   (2133571421L)
++#define EXT2_ET_RESIZE_INODE_CORRUPT             (2133571422L)
++#define EXT2_ET_SET_BMAP_NO_IND                  (2133571423L)
++
++#if 0
++extern const struct error_table et_ext2_error_table;
++extern void initialize_ext2_error_table(void);
++
++/* For compatibility with Heimdal */
++extern void initialize_ext2_error_table_r(struct et_list **list);
++
++#define ERROR_TABLE_BASE_ext2 (2133571328L)
++
++/* for compatibility with older versions... */
++#define init_ext2_err_tbl initialize_ext2_error_table
++#define ext2_err_base ERROR_TABLE_BASE_ext2
++#endif
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/ext2_ext_attr.h busybox/e2fsprogs/ext2fs/ext2_ext_attr.h
+--- busybox-1.00/e2fsprogs/ext2fs/ext2_ext_attr.h      1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/ext2_ext_attr.h   2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,69 @@
++/*
++  File: linux/ext2_ext_attr.h
++
++  On-disk format of extended attributes for the ext2 filesystem.
++
++  (C) 2000 Andreas Gruenbacher, <a.gruenbacher@computer.org>
++*/
++
++/* Magic value in attribute blocks */
++#define EXT2_EXT_ATTR_MAGIC_v1                0xEA010000
++#define EXT2_EXT_ATTR_MAGIC           0xEA020000
++
++/* Maximum number of references to one attribute block */
++#define EXT2_EXT_ATTR_REFCOUNT_MAX    1024
++
++struct ext2_ext_attr_header {
++      __u32   h_magic;        /* magic number for identification */
++      __u32   h_refcount;     /* reference count */
++      __u32   h_blocks;       /* number of disk blocks used */
++      __u32   h_hash;         /* hash value of all attributes */
++      __u32   h_reserved[4];  /* zero right now */
++};
++
++struct ext2_ext_attr_entry {
++      __u8    e_name_len;     /* length of name */
++      __u8    e_name_index;   /* attribute name index */
++      __u16   e_value_offs;   /* offset in disk block of value */
++      __u32   e_value_block;  /* disk block attribute is stored on (n/i) */
++      __u32   e_value_size;   /* size of attribute value */
++      __u32   e_hash;         /* hash value of name and value */
++#if 0
++      char    e_name[0];      /* attribute name */
++#endif
++};
++
++#define EXT2_EXT_ATTR_PAD_BITS                2
++#define EXT2_EXT_ATTR_PAD             (1<<EXT2_EXT_ATTR_PAD_BITS)
++#define EXT2_EXT_ATTR_ROUND           (EXT2_EXT_ATTR_PAD-1)
++#define EXT2_EXT_ATTR_LEN(name_len) \
++      (((name_len) + EXT2_EXT_ATTR_ROUND + \
++      sizeof(struct ext2_ext_attr_entry)) & ~EXT2_EXT_ATTR_ROUND)
++#define EXT2_EXT_ATTR_NEXT(entry) \
++      ( (struct ext2_ext_attr_entry *)( \
++        (char *)(entry) + EXT2_EXT_ATTR_LEN((entry)->e_name_len)) )
++#define EXT2_EXT_ATTR_SIZE(size) \
++      (((size) + EXT2_EXT_ATTR_ROUND) & ~EXT2_EXT_ATTR_ROUND)
++#define EXT2_EXT_IS_LAST_ENTRY(entry) (*((__u32 *)(entry)) == 0UL)
++#define EXT2_EXT_ATTR_NAME(entry) \
++      (((char *) (entry)) + sizeof(struct ext2_ext_attr_entry))
++#define EXT2_XATTR_LEN(name_len) \
++      (((name_len) + EXT2_EXT_ATTR_ROUND + \
++      sizeof(struct ext2_xattr_entry)) & ~EXT2_EXT_ATTR_ROUND)
++#define EXT2_XATTR_SIZE(size) \
++      (((size) + EXT2_EXT_ATTR_ROUND) & ~EXT2_EXT_ATTR_ROUND)
++
++#ifdef __KERNEL__
++# ifdef CONFIG_EXT2_FS_EXT_ATTR
++extern int ext2_get_ext_attr(struct inode *, const char *, char *, size_t, int);
++extern int ext2_set_ext_attr(struct inode *, const char *, char *, size_t, int);
++extern void ext2_ext_attr_free_inode(struct inode *inode);
++extern void ext2_ext_attr_put_super(struct super_block *sb);
++extern int ext2_ext_attr_init(void);
++extern void ext2_ext_attr_done(void);
++# else
++#  define ext2_get_ext_attr NULL
++#  define ext2_set_ext_attr NULL
++# endif
++#endif  /* __KERNEL__ */
++
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/ext2_fs.h busybox/e2fsprogs/ext2fs/ext2_fs.h
+--- busybox-1.00/e2fsprogs/ext2fs/ext2_fs.h    1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/ext2_fs.h 2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,644 @@
++/*
++ *  linux/include/linux/ext2_fs.h
++ *
++ * Copyright (C) 1992, 1993, 1994, 1995
++ * Remy Card (card@masi.ibp.fr)
++ * Laboratoire MASI - Institut Blaise Pascal
++ * Universite Pierre et Marie Curie (Paris VI)
++ *
++ *  from
++ *
++ *  linux/include/linux/minix_fs.h
++ *
++ *  Copyright (C) 1991, 1992  Linus Torvalds
++ */
++
++#ifndef _LINUX_EXT2_FS_H
++#define _LINUX_EXT2_FS_H
++
++#include <ext2fs/ext2_types.h>                /* Changed from linux/types.h */
++
++/*
++ * The second extended filesystem constants/structures
++ */
++
++/*
++ * Define EXT2FS_DEBUG to produce debug messages
++ */
++#undef EXT2FS_DEBUG
++
++/*
++ * Define EXT2_PREALLOCATE to preallocate data blocks for expanding files
++ */
++#define EXT2_PREALLOCATE
++#define EXT2_DEFAULT_PREALLOC_BLOCKS  8
++
++/*
++ * The second extended file system version
++ */
++#define EXT2FS_DATE           "95/08/09"
++#define EXT2FS_VERSION                "0.5b"
++
++/*
++ * Special inode numbers
++ */
++#define EXT2_BAD_INO           1      /* Bad blocks inode */
++#define EXT2_ROOT_INO          2      /* Root inode */
++#define EXT2_ACL_IDX_INO       3      /* ACL inode */
++#define EXT2_ACL_DATA_INO      4      /* ACL inode */
++#define EXT2_BOOT_LOADER_INO   5      /* Boot loader inode */
++#define EXT2_UNDEL_DIR_INO     6      /* Undelete directory inode */
++#define EXT2_RESIZE_INO                7      /* Reserved group descriptors inode */
++#define EXT2_JOURNAL_INO       8      /* Journal inode */
++
++/* First non-reserved inode for old ext2 filesystems */
++#define EXT2_GOOD_OLD_FIRST_INO       11
++
++/*
++ * The second extended file system magic number
++ */
++#define EXT2_SUPER_MAGIC      0xEF53
++
++#ifdef __KERNEL__
++#define EXT2_SB(sb)   (&((sb)->u.ext2_sb))
++#else
++/* Assume that user mode programs are passing in an ext2fs superblock, not
++ * a kernel struct super_block.  This will allow us to call the feature-test
++ * macros from user land. */
++#define EXT2_SB(sb)   (sb)
++#endif
++
++/*
++ * Maximal count of links to a file
++ */
++#define EXT2_LINK_MAX         32000
++
++/*
++ * Macro-instructions used to manage several block sizes
++ */
++#define EXT2_MIN_BLOCK_LOG_SIZE               10      /* 1024 */
++#define EXT2_MAX_BLOCK_LOG_SIZE               16      /* 65536 */
++#define EXT2_MIN_BLOCK_SIZE   (1 << EXT2_MIN_BLOCK_LOG_SIZE)
++#define EXT2_MAX_BLOCK_SIZE   (1 << EXT2_MAX_BLOCK_LOG_SIZE)
++#ifdef __KERNEL__
++#define EXT2_BLOCK_SIZE(s)    ((s)->s_blocksize)
++#define EXT2_BLOCK_SIZE_BITS(s)       ((s)->s_blocksize_bits)
++#define EXT2_ADDR_PER_BLOCK_BITS(s)   (EXT2_SB(s)->addr_per_block_bits)
++#define EXT2_INODE_SIZE(s)    (EXT2_SB(s)->s_inode_size)
++#define EXT2_FIRST_INO(s)     (EXT2_SB(s)->s_first_ino)
++#else
++#define EXT2_BLOCK_SIZE(s)    (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size)
++#define EXT2_BLOCK_SIZE_BITS(s)       ((s)->s_log_block_size + 10)
++#define EXT2_INODE_SIZE(s)    (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
++                               EXT2_GOOD_OLD_INODE_SIZE : (s)->s_inode_size)
++#define EXT2_FIRST_INO(s)     (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
++                               EXT2_GOOD_OLD_FIRST_INO : (s)->s_first_ino)
++#endif
++#define EXT2_ADDR_PER_BLOCK(s)        (EXT2_BLOCK_SIZE(s) / sizeof(__u32))
++
++/*
++ * Macro-instructions used to manage fragments
++ */
++#define EXT2_MIN_FRAG_SIZE            EXT2_MIN_BLOCK_SIZE
++#define EXT2_MAX_FRAG_SIZE            EXT2_MAX_BLOCK_SIZE
++#define EXT2_MIN_FRAG_LOG_SIZE                EXT2_MIN_BLOCK_LOG_SIZE
++#ifdef __KERNEL__
++# define EXT2_FRAG_SIZE(s)            (EXT2_SB(s)->s_frag_size)
++# define EXT2_FRAGS_PER_BLOCK(s)      (EXT2_SB(s)->s_frags_per_block)
++#else
++# define EXT2_FRAG_SIZE(s)            (EXT2_MIN_FRAG_SIZE << (s)->s_log_frag_size)
++# define EXT2_FRAGS_PER_BLOCK(s)      (EXT2_BLOCK_SIZE(s) / EXT2_FRAG_SIZE(s))
++#endif
++
++/*
++ * ACL structures
++ */
++struct ext2_acl_header        /* Header of Access Control Lists */
++{
++      __u32   aclh_size;
++      __u32   aclh_file_count;
++      __u32   aclh_acle_count;
++      __u32   aclh_first_acle;
++};
++
++struct ext2_acl_entry /* Access Control List Entry */
++{
++      __u32   acle_size;
++      __u16   acle_perms;     /* Access permissions */
++      __u16   acle_type;      /* Type of entry */
++      __u16   acle_tag;       /* User or group identity */
++      __u16   acle_pad1;
++      __u32   acle_next;      /* Pointer on next entry for the */
++                                      /* same inode or on next free entry */
++};
++
++/*
++ * Structure of a blocks group descriptor
++ */
++struct ext2_group_desc
++{
++      __u32   bg_block_bitmap;                /* Blocks bitmap block */
++      __u32   bg_inode_bitmap;                /* Inodes bitmap block */
++      __u32   bg_inode_table;         /* Inodes table block */
++      __u16   bg_free_blocks_count;   /* Free blocks count */
++      __u16   bg_free_inodes_count;   /* Free inodes count */
++      __u16   bg_used_dirs_count;     /* Directories count */
++      __u16   bg_pad;
++      __u32   bg_reserved[3];
++};
++
++/*
++ * Data structures used by the directory indexing feature
++ *
++ * Note: all of the multibyte integer fields are little endian.
++ */
++
++/*
++ * Note: dx_root_info is laid out so that if it should somehow get
++ * overlaid by a dirent the two low bits of the hash version will be
++ * zero.  Therefore, the hash version mod 4 should never be 0.
++ * Sincerely, the paranoia department.
++ */
++struct ext2_dx_root_info {
++      __u32 reserved_zero;
++      __u8 hash_version; /* 0 now, 1 at release */
++      __u8 info_length; /* 8 */
++      __u8 indirect_levels;
++      __u8 unused_flags;
++};
++
++#define EXT2_HASH_LEGACY      0
++#define EXT2_HASH_HALF_MD4    1
++#define EXT2_HASH_TEA         2
++
++#define EXT2_HASH_FLAG_INCOMPAT       0x1
++
++struct ext2_dx_entry {
++      __u32 hash;
++      __u32 block;
++};
++
++struct ext2_dx_countlimit {
++      __u16 limit;
++      __u16 count;
++};
++
++
++/*
++ * Macro-instructions used to manage group descriptors
++ */
++#define EXT2_BLOCKS_PER_GROUP(s)      (EXT2_SB(s)->s_blocks_per_group)
++#define EXT2_INODES_PER_GROUP(s)      (EXT2_SB(s)->s_inodes_per_group)
++#define EXT2_INODES_PER_BLOCK(s)      (EXT2_BLOCK_SIZE(s)/EXT2_INODE_SIZE(s))
++/* limits imposed by 16-bit value gd_free_{blocks,inode}_count */
++#define EXT2_MAX_BLOCKS_PER_GROUP(s)  ((1 << 16) - 8)
++#define EXT2_MAX_INODES_PER_GROUP(s)  ((1 << 16) - EXT2_INODES_PER_BLOCK(s))
++#ifdef __KERNEL__
++#define EXT2_DESC_PER_BLOCK(s)                (EXT2_SB(s)->s_desc_per_block)
++#define EXT2_DESC_PER_BLOCK_BITS(s)   (EXT2_SB(s)->s_desc_per_block_bits)
++#else
++#define EXT2_DESC_PER_BLOCK(s)                (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc))
++#endif
++
++/*
++ * Constants relative to the data blocks
++ */
++#define EXT2_NDIR_BLOCKS              12
++#define EXT2_IND_BLOCK                        EXT2_NDIR_BLOCKS
++#define EXT2_DIND_BLOCK                       (EXT2_IND_BLOCK + 1)
++#define EXT2_TIND_BLOCK                       (EXT2_DIND_BLOCK + 1)
++#define EXT2_N_BLOCKS                 (EXT2_TIND_BLOCK + 1)
++
++/*
++ * Inode flags
++ */
++#define EXT2_SECRM_FL                 0x00000001 /* Secure deletion */
++#define EXT2_UNRM_FL                  0x00000002 /* Undelete */
++#define EXT2_COMPR_FL                 0x00000004 /* Compress file */
++#define EXT2_SYNC_FL                  0x00000008 /* Synchronous updates */
++#define EXT2_IMMUTABLE_FL             0x00000010 /* Immutable file */
++#define EXT2_APPEND_FL                        0x00000020 /* writes to file may only append */
++#define EXT2_NODUMP_FL                        0x00000040 /* do not dump file */
++#define EXT2_NOATIME_FL                       0x00000080 /* do not update atime */
++/* Reserved for compression usage... */
++#define EXT2_DIRTY_FL                 0x00000100
++#define EXT2_COMPRBLK_FL              0x00000200 /* One or more compressed clusters */
++#define EXT2_NOCOMPR_FL                       0x00000400 /* Access raw compressed data */
++#define EXT2_ECOMPR_FL                        0x00000800 /* Compression error */
++/* End compression flags --- maybe not all used */
++#define EXT2_BTREE_FL                 0x00001000 /* btree format dir */
++#define EXT2_INDEX_FL                 0x00001000 /* hash-indexed directory */
++#define EXT2_IMAGIC_FL                        0x00002000
++#define EXT3_JOURNAL_DATA_FL          0x00004000 /* file data should be journaled */
++#define EXT2_NOTAIL_FL                        0x00008000 /* file tail should not be merged */
++#define EXT2_DIRSYNC_FL               0x00010000 /* Synchronous directory modifications */
++#define EXT2_TOPDIR_FL                        0x00020000 /* Top of directory hierarchies*/
++#define EXT3_EXTENTS_FL               0x00080000 /* Inode uses extents */
++#define EXT2_RESERVED_FL              0x80000000 /* reserved for ext2 lib */
++
++#define EXT2_FL_USER_VISIBLE          0x0003DFFF /* User visible flags */
++#define EXT2_FL_USER_MODIFIABLE               0x000080FF /* User modifiable flags */
++
++/*
++ * ioctl commands
++ */
++#define EXT2_IOC_GETFLAGS             _IOR('f', 1, long)
++#define EXT2_IOC_SETFLAGS             _IOW('f', 2, long)
++#define EXT2_IOC_GETVERSION           _IOR('v', 1, long)
++#define EXT2_IOC_SETVERSION           _IOW('v', 2, long)
++
++/*
++ * Structure of an inode on the disk
++ */
++struct ext2_inode {
++      __u16   i_mode;         /* File mode */
++      __u16   i_uid;          /* Low 16 bits of Owner Uid */
++      __u32   i_size;         /* Size in bytes */
++      __u32   i_atime;        /* Access time */
++      __u32   i_ctime;        /* Creation time */
++      __u32   i_mtime;        /* Modification time */
++      __u32   i_dtime;        /* Deletion Time */
++      __u16   i_gid;          /* Low 16 bits of Group Id */
++      __u16   i_links_count;  /* Links count */
++      __u32   i_blocks;       /* Blocks count */
++      __u32   i_flags;        /* File flags */
++      union {
++              struct {
++                      __u32  l_i_reserved1;
++              } linux1;
++              struct {
++                      __u32  h_i_translator;
++              } hurd1;
++              struct {
++                      __u32  m_i_reserved1;
++              } masix1;
++      } osd1;                         /* OS dependent 1 */
++      __u32   i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
++      __u32   i_generation;   /* File version (for NFS) */
++      __u32   i_file_acl;     /* File ACL */
++      __u32   i_dir_acl;      /* Directory ACL */
++      __u32   i_faddr;        /* Fragment address */
++      union {
++              struct {
++                      __u8    l_i_frag;       /* Fragment number */
++                      __u8    l_i_fsize;      /* Fragment size */
++                      __u16   i_pad1;
++                      __u16   l_i_uid_high;   /* these 2 fields    */
++                      __u16   l_i_gid_high;   /* were reserved2[0] */
++                      __u32   l_i_reserved2;
++              } linux2;
++              struct {
++                      __u8    h_i_frag;       /* Fragment number */
++                      __u8    h_i_fsize;      /* Fragment size */
++                      __u16   h_i_mode_high;
++                      __u16   h_i_uid_high;
++                      __u16   h_i_gid_high;
++                      __u32   h_i_author;
++              } hurd2;
++              struct {
++                      __u8    m_i_frag;       /* Fragment number */
++                      __u8    m_i_fsize;      /* Fragment size */
++                      __u16   m_pad1;
++                      __u32   m_i_reserved2[2];
++              } masix2;
++      } osd2;                         /* OS dependent 2 */
++};
++
++/*
++ * Permanent part of an large inode on the disk
++ */
++struct ext2_inode_large {
++      __u16   i_mode;         /* File mode */
++      __u16   i_uid;          /* Low 16 bits of Owner Uid */
++      __u32   i_size;         /* Size in bytes */
++      __u32   i_atime;        /* Access time */
++      __u32   i_ctime;        /* Creation time */
++      __u32   i_mtime;        /* Modification time */
++      __u32   i_dtime;        /* Deletion Time */
++      __u16   i_gid;          /* Low 16 bits of Group Id */
++      __u16   i_links_count;  /* Links count */
++      __u32   i_blocks;       /* Blocks count */
++      __u32   i_flags;        /* File flags */
++      union {
++              struct {
++                      __u32  l_i_reserved1;
++              } linux1;
++              struct {
++                      __u32  h_i_translator;
++              } hurd1;
++              struct {
++                      __u32  m_i_reserved1;
++              } masix1;
++      } osd1;                         /* OS dependent 1 */
++      __u32   i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
++      __u32   i_generation;   /* File version (for NFS) */
++      __u32   i_file_acl;     /* File ACL */
++      __u32   i_dir_acl;      /* Directory ACL */
++      __u32   i_faddr;        /* Fragment address */
++      union {
++              struct {
++                      __u8    l_i_frag;       /* Fragment number */
++                      __u8    l_i_fsize;      /* Fragment size */
++                      __u16   i_pad1;
++                      __u16   l_i_uid_high;   /* these 2 fields    */
++                      __u16   l_i_gid_high;   /* were reserved2[0] */
++                      __u32   l_i_reserved2;
++              } linux2;
++              struct {
++                      __u8    h_i_frag;       /* Fragment number */
++                      __u8    h_i_fsize;      /* Fragment size */
++                      __u16   h_i_mode_high;
++                      __u16   h_i_uid_high;
++                      __u16   h_i_gid_high;
++                      __u32   h_i_author;
++              } hurd2;
++              struct {
++                      __u8    m_i_frag;       /* Fragment number */
++                      __u8    m_i_fsize;      /* Fragment size */
++                      __u16   m_pad1;
++                      __u32   m_i_reserved2[2];
++              } masix2;
++      } osd2;                         /* OS dependent 2 */
++      __u16   i_extra_isize;
++      __u16   i_pad1;
++};
++
++#define i_size_high   i_dir_acl
++
++#if defined(__KERNEL__) || defined(__linux__)
++#define i_reserved1   osd1.linux1.l_i_reserved1
++#define i_frag                osd2.linux2.l_i_frag
++#define i_fsize               osd2.linux2.l_i_fsize
++#define i_uid_low     i_uid
++#define i_gid_low     i_gid
++#define i_uid_high    osd2.linux2.l_i_uid_high
++#define i_gid_high    osd2.linux2.l_i_gid_high
++#define i_reserved2   osd2.linux2.l_i_reserved2
++
++#else
++#if defined(__GNU__)
++
++#define i_translator  osd1.hurd1.h_i_translator
++#define i_frag                osd2.hurd2.h_i_frag;
++#define i_fsize               osd2.hurd2.h_i_fsize;
++#define i_uid_high    osd2.hurd2.h_i_uid_high
++#define i_gid_high    osd2.hurd2.h_i_gid_high
++#define i_author      osd2.hurd2.h_i_author
++
++#else
++#if defined(__masix__)
++
++#define i_reserved1   osd1.masix1.m_i_reserved1
++#define i_frag                osd2.masix2.m_i_frag
++#define i_fsize               osd2.masix2.m_i_fsize
++#define i_reserved2   osd2.masix2.m_i_reserved2
++
++#endif  /* __masix__ */
++#endif  /* __GNU__ */
++#endif        /* defined(__KERNEL__) || defined(__linux__) */
++
++/*
++ * File system states
++ */
++#define EXT2_VALID_FS                 0x0001  /* Unmounted cleanly */
++#define EXT2_ERROR_FS                 0x0002  /* Errors detected */
++
++/*
++ * Mount flags
++ */
++#define EXT2_MOUNT_CHECK              0x0001  /* Do mount-time checks */
++#define EXT2_MOUNT_GRPID              0x0004  /* Create files with directory's group */
++#define EXT2_MOUNT_DEBUG              0x0008  /* Some debugging messages */
++#define EXT2_MOUNT_ERRORS_CONT                0x0010  /* Continue on errors */
++#define EXT2_MOUNT_ERRORS_RO          0x0020  /* Remount fs ro on errors */
++#define EXT2_MOUNT_ERRORS_PANIC               0x0040  /* Panic on errors */
++#define EXT2_MOUNT_MINIX_DF           0x0080  /* Mimics the Minix statfs */
++#define EXT2_MOUNT_NO_UID32           0x0200  /* Disable 32-bit UIDs */
++
++#define clear_opt(o, opt)             o &= ~EXT2_MOUNT_##opt
++#define set_opt(o, opt)                       o |= EXT2_MOUNT_##opt
++#define test_opt(sb, opt)             (EXT2_SB(sb)->s_mount_opt & \
++                                       EXT2_MOUNT_##opt)
++/*
++ * Maximal mount counts between two filesystem checks
++ */
++#define EXT2_DFL_MAX_MNT_COUNT                20      /* Allow 20 mounts */
++#define EXT2_DFL_CHECKINTERVAL                0       /* Don't use interval check */
++
++/*
++ * Behaviour when detecting errors
++ */
++#define EXT2_ERRORS_CONTINUE          1       /* Continue execution */
++#define EXT2_ERRORS_RO                        2       /* Remount fs read-only */
++#define EXT2_ERRORS_PANIC             3       /* Panic */
++#define EXT2_ERRORS_DEFAULT           EXT2_ERRORS_CONTINUE
++
++/*
++ * Structure of the super block
++ */
++struct ext2_super_block {
++      __u32   s_inodes_count;         /* Inodes count */
++      __u32   s_blocks_count;         /* Blocks count */
++      __u32   s_r_blocks_count;       /* Reserved blocks count */
++      __u32   s_free_blocks_count;    /* Free blocks count */
++      __u32   s_free_inodes_count;    /* Free inodes count */
++      __u32   s_first_data_block;     /* First Data Block */
++      __u32   s_log_block_size;       /* Block size */
++      __s32   s_log_frag_size;        /* Fragment size */
++      __u32   s_blocks_per_group;     /* # Blocks per group */
++      __u32   s_frags_per_group;      /* # Fragments per group */
++      __u32   s_inodes_per_group;     /* # Inodes per group */
++      __u32   s_mtime;                /* Mount time */
++      __u32   s_wtime;                /* Write time */
++      __u16   s_mnt_count;            /* Mount count */
++      __s16   s_max_mnt_count;        /* Maximal mount count */
++      __u16   s_magic;                /* Magic signature */
++      __u16   s_state;                /* File system state */
++      __u16   s_errors;               /* Behaviour when detecting errors */
++      __u16   s_minor_rev_level;      /* minor revision level */
++      __u32   s_lastcheck;            /* time of last check */
++      __u32   s_checkinterval;        /* max. time between checks */
++      __u32   s_creator_os;           /* OS */
++      __u32   s_rev_level;            /* Revision level */
++      __u16   s_def_resuid;           /* Default uid for reserved blocks */
++      __u16   s_def_resgid;           /* Default gid for reserved blocks */
++      /*
++       * These fields are for EXT2_DYNAMIC_REV superblocks only.
++       *
++       * Note: the difference between the compatible feature set and
++       * the incompatible feature set is that if there is a bit set
++       * in the incompatible feature set that the kernel doesn't
++       * know about, it should refuse to mount the filesystem.
++       *
++       * e2fsck's requirements are more strict; if it doesn't know
++       * about a feature in either the compatible or incompatible
++       * feature set, it must abort and not try to meddle with
++       * things it doesn't understand...
++       */
++      __u32   s_first_ino;            /* First non-reserved inode */
++      __u16   s_inode_size;           /* size of inode structure */
++      __u16   s_block_group_nr;       /* block group # of this superblock */
++      __u32   s_feature_compat;       /* compatible feature set */
++      __u32   s_feature_incompat;     /* incompatible feature set */
++      __u32   s_feature_ro_compat;    /* readonly-compatible feature set */
++      __u8    s_uuid[16];             /* 128-bit uuid for volume */
++      char    s_volume_name[16];      /* volume name */
++      char    s_last_mounted[64];     /* directory where last mounted */
++      __u32   s_algorithm_usage_bitmap; /* For compression */
++      /*
++       * Performance hints.  Directory preallocation should only
++       * happen if the EXT2_FEATURE_COMPAT_DIR_PREALLOC flag is on.
++       */
++      __u8    s_prealloc_blocks;      /* Nr of blocks to try to preallocate*/
++      __u8    s_prealloc_dir_blocks;  /* Nr to preallocate for dirs */
++      __u16   s_reserved_gdt_blocks;  /* Per group table for online growth */
++      /*
++       * Journaling support valid if EXT2_FEATURE_COMPAT_HAS_JOURNAL set.
++       */
++      __u8    s_journal_uuid[16];     /* uuid of journal superblock */
++      __u32   s_journal_inum;         /* inode number of journal file */
++      __u32   s_journal_dev;          /* device number of journal file */
++      __u32   s_last_orphan;          /* start of list of inodes to delete */
++      __u32   s_hash_seed[4];         /* HTREE hash seed */
++      __u8    s_def_hash_version;     /* Default hash version to use */
++      __u8    s_jnl_backup_type;      /* Default type of journal backup */
++      __u16   s_reserved_word_pad;
++      __u32   s_default_mount_opts;
++      __u32   s_first_meta_bg;        /* First metablock group */
++      __u32   s_mkfs_time;            /* When the filesystem was created */
++      __u32   s_jnl_blocks[17];       /* Backup of the journal inode */
++      __u32   s_reserved[172];        /* Padding to the end of the block */
++};
++
++/*
++ * Codes for operating systems
++ */
++#define EXT2_OS_LINUX         0
++#define EXT2_OS_HURD          1
++#define EXT2_OS_MASIX         2
++#define EXT2_OS_FREEBSD               3
++#define EXT2_OS_LITES         4
++
++/*
++ * Revision levels
++ */
++#define EXT2_GOOD_OLD_REV     0       /* The good old (original) format */
++#define EXT2_DYNAMIC_REV      1       /* V2 format w/ dynamic inode sizes */
++
++#define EXT2_CURRENT_REV      EXT2_GOOD_OLD_REV
++#define EXT2_MAX_SUPP_REV     EXT2_DYNAMIC_REV
++
++#define EXT2_GOOD_OLD_INODE_SIZE 128
++
++/*
++ * Journal inode backup types
++ */
++#define EXT3_JNL_BACKUP_BLOCKS        1
++
++/*
++ * Feature set definitions
++ */
++
++#define EXT2_HAS_COMPAT_FEATURE(sb,mask)                      \
++      ( EXT2_SB(sb)->s_feature_compat & (mask) )
++#define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask)                   \
++      ( EXT2_SB(sb)->s_feature_ro_compat & (mask) )
++#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask)                    \
++      ( EXT2_SB(sb)->s_feature_incompat & (mask) )
++
++#define EXT2_FEATURE_COMPAT_DIR_PREALLOC      0x0001
++#define EXT2_FEATURE_COMPAT_IMAGIC_INODES     0x0002
++#define EXT3_FEATURE_COMPAT_HAS_JOURNAL               0x0004
++#define EXT2_FEATURE_COMPAT_EXT_ATTR          0x0008
++#define EXT2_FEATURE_COMPAT_RESIZE_INODE      0x0010
++#define EXT2_FEATURE_COMPAT_DIR_INDEX         0x0020
++
++#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER   0x0001
++#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE     0x0002
++/* #define EXT2_FEATURE_RO_COMPAT_BTREE_DIR   0x0004 not used */
++
++#define EXT2_FEATURE_INCOMPAT_COMPRESSION     0x0001
++#define EXT2_FEATURE_INCOMPAT_FILETYPE                0x0002
++#define EXT3_FEATURE_INCOMPAT_RECOVER         0x0004 /* Needs recovery */
++#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV     0x0008 /* Journal device */
++#define EXT2_FEATURE_INCOMPAT_META_BG         0x0010
++#define EXT3_FEATURE_INCOMPAT_EXTENTS         0x0040
++
++
++#define EXT2_FEATURE_COMPAT_SUPP      0
++#define EXT2_FEATURE_INCOMPAT_SUPP    (EXT2_FEATURE_INCOMPAT_FILETYPE)
++#define EXT2_FEATURE_RO_COMPAT_SUPP   (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
++                                       EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
++                                       EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
++
++/*
++ * Default values for user and/or group using reserved blocks
++ */
++#define EXT2_DEF_RESUID               0
++#define EXT2_DEF_RESGID               0
++
++/*
++ * Default mount options
++ */
++#define EXT2_DEFM_DEBUG               0x0001
++#define EXT2_DEFM_BSDGROUPS   0x0002
++#define EXT2_DEFM_XATTR_USER  0x0004
++#define EXT2_DEFM_ACL         0x0008
++#define EXT2_DEFM_UID16               0x0010
++#define EXT3_DEFM_JMODE               0x0060 
++#define EXT3_DEFM_JMODE_DATA  0x0020
++#define EXT3_DEFM_JMODE_ORDERED       0x0040
++#define EXT3_DEFM_JMODE_WBACK 0x0060
++
++/*
++ * Structure of a directory entry
++ */
++#define EXT2_NAME_LEN 255
++
++struct ext2_dir_entry {
++      __u32   inode;                  /* Inode number */
++      __u16   rec_len;                /* Directory entry length */
++      __u16   name_len;               /* Name length */
++      char    name[EXT2_NAME_LEN];    /* File name */
++};
++
++/*
++ * The new version of the directory entry.  Since EXT2 structures are
++ * stored in intel byte order, and the name_len field could never be
++ * bigger than 255 chars, it's safe to reclaim the extra byte for the
++ * file_type field.
++ */
++struct ext2_dir_entry_2 {
++      __u32   inode;                  /* Inode number */
++      __u16   rec_len;                /* Directory entry length */
++      __u8    name_len;               /* Name length */
++      __u8    file_type;
++      char    name[EXT2_NAME_LEN];    /* File name */
++};
++
++/*
++ * Ext2 directory file types.  Only the low 3 bits are used.  The
++ * other bits are reserved for now.
++ */
++#define EXT2_FT_UNKNOWN               0
++#define EXT2_FT_REG_FILE      1
++#define EXT2_FT_DIR           2
++#define EXT2_FT_CHRDEV                3
++#define EXT2_FT_BLKDEV                4
++#define EXT2_FT_FIFO          5
++#define EXT2_FT_SOCK          6
++#define EXT2_FT_SYMLINK               7
++
++#define EXT2_FT_MAX           8
++
++/*
++ * EXT2_DIR_PAD defines the directory entries boundaries
++ *
++ * NOTE: It must be a multiple of 4
++ */
++#define EXT2_DIR_PAD                  4
++#define EXT2_DIR_ROUND                        (EXT2_DIR_PAD - 1)
++#define EXT2_DIR_REC_LEN(name_len)    (((name_len) + 8 + EXT2_DIR_ROUND) & \
++                                       ~EXT2_DIR_ROUND)
++
++#endif        /* _LINUX_EXT2_FS_H */
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/ext2_io.h busybox/e2fsprogs/ext2fs/ext2_io.h
+--- busybox-1.00/e2fsprogs/ext2fs/ext2_io.h    1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/ext2_io.h 2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,108 @@
++/*
++ * io.h --- the I/O manager abstraction
++ * 
++ * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#ifndef _EXT2FS_EXT2_IO_H
++#define _EXT2FS_EXT2_IO_H
++
++/*
++ * ext2_loff_t is defined here since unix_io.c needs it.
++ */
++#if defined(__GNUC__) || defined(HAS_LONG_LONG)
++typedef long long     ext2_loff_t;
++#else
++typedef long          ext2_loff_t;
++#endif
++
++/* llseek.c */
++ext2_loff_t ext2fs_llseek (int, ext2_loff_t, int);
++
++typedef struct struct_io_manager *io_manager;
++typedef struct struct_io_channel *io_channel;
++
++#define CHANNEL_FLAGS_WRITETHROUGH    0x01
++
++struct struct_io_channel {
++      errcode_t       magic;
++      io_manager      manager;
++      char            *name;
++      int             block_size;
++      errcode_t       (*read_error)(io_channel channel,
++                                    unsigned long block,
++                                    int count,
++                                    void *data,
++                                    size_t size,
++                                    int actual_bytes_read,
++                                    errcode_t error);
++      errcode_t       (*write_error)(io_channel channel,
++                                     unsigned long block,
++                                     int count,
++                                     const void *data,
++                                     size_t size,
++                                     int actual_bytes_written,
++                                     errcode_t error);
++      int             refcount;
++      int             flags;
++      int             reserved[14];
++      void            *private_data;
++      void            *app_data;
++};
++
++struct struct_io_manager {
++      errcode_t magic;
++      const char *name;
++      errcode_t (*open)(const char *name, int flags, io_channel *channel);
++      errcode_t (*close)(io_channel channel);
++      errcode_t (*set_blksize)(io_channel channel, int blksize);
++      errcode_t (*read_blk)(io_channel channel, unsigned long block,
++                            int count, void *data);
++      errcode_t (*write_blk)(io_channel channel, unsigned long block,
++                             int count, const void *data);
++      errcode_t (*flush)(io_channel channel);
++      errcode_t (*write_byte)(io_channel channel, unsigned long offset,
++                              int count, const void *data);
++      errcode_t (*set_option)(io_channel channel, const char *option, 
++                              const char *arg);
++      int             reserved[14];
++};
++
++#define IO_FLAG_RW    1
++
++/*
++ * Convenience functions....
++ */
++#define io_channel_close(c)           ((c)->manager->close((c)))
++#define io_channel_set_blksize(c,s)   ((c)->manager->set_blksize((c),s))
++#define io_channel_read_blk(c,b,n,d)  ((c)->manager->read_blk((c),b,n,d))
++#define io_channel_write_blk(c,b,n,d) ((c)->manager->write_blk((c),b,n,d))
++#define io_channel_flush(c)           ((c)->manager->flush((c)))
++#define io_channel_bumpcount(c)               ((c)->refcount++)
++      
++/* io_manager.c */
++extern errcode_t io_channel_set_options(io_channel channel, 
++                                      const char *options);
++extern errcode_t io_channel_write_byte(io_channel channel, 
++                                     unsigned long offset,
++                                     int count, const void *data);
++
++/* unix_io.c */
++extern io_manager unix_io_manager;
++
++/* test_io.c */
++extern io_manager test_io_manager, test_io_backing_manager;
++extern void (*test_io_cb_read_blk)
++      (unsigned long block, int count, errcode_t err);
++extern void (*test_io_cb_write_blk)
++      (unsigned long block, int count, errcode_t err);
++extern void (*test_io_cb_set_blksize)
++      (int blksize, errcode_t err);
++
++#endif /* _EXT2FS_EXT2_IO_H */
++      
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/ext2_types.h busybox/e2fsprogs/ext2fs/ext2_types.h
+--- busybox-1.00/e2fsprogs/ext2fs/ext2_types.h 1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/ext2_types.h      2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1 @@
++#include <linux/types.h>
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/ext2fs.h busybox/e2fsprogs/ext2fs/ext2fs.h
+--- busybox-1.00/e2fsprogs/ext2fs/ext2fs.h     1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/ext2fs.h  2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,1137 @@
++/*
++ * ext2fs.h --- ext2fs
++ * 
++ * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#ifndef _EXT2FS_EXT2FS_H
++#define _EXT2FS_EXT2FS_H
++
++#ifdef __GNUC__
++#define EXT2FS_ATTR(x) __attribute__(x)
++#else
++#define EXT2FS_ATTR(x)
++#endif
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/*
++ * Non-GNU C compilers won't necessarily understand inline
++ */
++#if (!defined(__GNUC__) && !defined(__WATCOMC__))
++#define NO_INLINE_FUNCS
++#endif
++
++/*
++ * Build in support for byte-swapping filesystems if we the feature
++ * has been configured or if we're being built on a CPU architecture
++ * with a non-native byte order.
++ */
++#if defined(ENABLE_SWAPFS) || defined(WORDS_BIGENDIAN)
++#define EXT2FS_ENABLE_SWAPFS
++#endif
++
++/*
++ * Where the master copy of the superblock is located, and how big
++ * superblocks are supposed to be.  We define SUPERBLOCK_SIZE because
++ * the size of the superblock structure is not necessarily trustworthy
++ * (some versions have the padding set up so that the superblock is
++ * 1032 bytes long).
++ */
++#define SUPERBLOCK_OFFSET     1024
++#define SUPERBLOCK_SIZE       1024
++
++/*
++ * The last ext2fs revision level that this version of the library is
++ * able to support.
++ */
++#define EXT2_LIB_CURRENT_REV  EXT2_DYNAMIC_REV
++
++#ifdef HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++
++#include <stdio.h>
++#include <stdlib.h>
++
++#if EXT2_FLAT_INCLUDES
++#include "e2_types.h"
++#include "ext2_fs.h"
++#else
++#include <ext2fs/ext2_types.h>
++#include <ext2fs/ext2_fs.h>
++#endif /* EXT2_FLAT_INCLUDES */
++
++typedef __u32         ext2_ino_t;
++typedef __u32         blk_t;
++typedef __u32         dgrp_t;
++typedef __u32         ext2_off_t;
++typedef __s64         e2_blkcnt_t;
++typedef __u32         ext2_dirhash_t;
++
++#if EXT2_FLAT_INCLUDES
++#include "com_err.h"
++#include "ext2_io.h"
++#include "ext2_err.h"
++#else
++#include <et/com_err.h>
++#include <ext2fs/ext2_io.h>
++#include <ext2fs/ext2_err.h>
++#endif
++
++/*
++ * Portability help for Microsoft Visual C++
++ */
++#ifdef _MSC_VER
++#define EXT2_QSORT_TYPE int __cdecl
++#else
++#define EXT2_QSORT_TYPE int
++#endif
++
++typedef struct struct_ext2_filsys *ext2_filsys;
++
++struct ext2fs_struct_generic_bitmap {
++      errcode_t       magic;
++      ext2_filsys     fs;
++      __u32           start, end;
++      __u32           real_end;
++      char    *       description;
++      char    *       bitmap;
++      errcode_t       base_error_code;
++      __u32           reserved[7];
++};
++
++#define EXT2FS_MARK_ERROR     0
++#define EXT2FS_UNMARK_ERROR   1
++#define EXT2FS_TEST_ERROR     2
++
++typedef struct ext2fs_struct_generic_bitmap *ext2fs_generic_bitmap;
++typedef struct ext2fs_struct_generic_bitmap *ext2fs_inode_bitmap;
++typedef struct ext2fs_struct_generic_bitmap *ext2fs_block_bitmap;
++
++#ifdef EXT2_DYNAMIC_REV
++#define EXT2_FIRST_INODE(s)   EXT2_FIRST_INO(s)
++#else
++#define EXT2_FIRST_INODE(s)   EXT2_FIRST_INO
++#define EXT2_INODE_SIZE(s)    sizeof(struct ext2_inode)
++#endif
++
++/*
++ * badblocks list definitions
++ */
++
++typedef struct ext2_struct_u32_list *ext2_badblocks_list;
++typedef struct ext2_struct_u32_iterate *ext2_badblocks_iterate;
++
++typedef struct ext2_struct_u32_list *ext2_u32_list;
++typedef struct ext2_struct_u32_iterate *ext2_u32_iterate;
++
++/* old */
++typedef struct ext2_struct_u32_list *badblocks_list;
++typedef struct ext2_struct_u32_iterate *badblocks_iterate;
++
++#define BADBLOCKS_FLAG_DIRTY  1
++
++/*
++ * ext2_dblist structure and abstractions (see dblist.c)
++ */
++struct ext2_db_entry {
++      ext2_ino_t      ino;
++      blk_t   blk;
++      int     blockcnt;
++};
++
++typedef struct ext2_struct_dblist *ext2_dblist;
++
++#define DBLIST_ABORT  1
++
++/*
++ * ext2_fileio definitions
++ */
++
++#define EXT2_FILE_WRITE               0x0001
++#define EXT2_FILE_CREATE      0x0002
++
++#define EXT2_FILE_MASK                0x00FF
++
++#define EXT2_FILE_BUF_DIRTY   0x4000
++#define EXT2_FILE_BUF_VALID   0x2000
++
++typedef struct ext2_file *ext2_file_t;
++
++#define EXT2_SEEK_SET 0
++#define EXT2_SEEK_CUR 1
++#define EXT2_SEEK_END 2
++
++/*
++ * Flags for the ext2_filsys structure and for ext2fs_open()
++ */
++#define EXT2_FLAG_RW                  0x01
++#define EXT2_FLAG_CHANGED             0x02
++#define EXT2_FLAG_DIRTY                       0x04
++#define EXT2_FLAG_VALID                       0x08
++#define EXT2_FLAG_IB_DIRTY            0x10
++#define EXT2_FLAG_BB_DIRTY            0x20
++#define EXT2_FLAG_SWAP_BYTES          0x40
++#define EXT2_FLAG_SWAP_BYTES_READ     0x80
++#define EXT2_FLAG_SWAP_BYTES_WRITE    0x100
++#define EXT2_FLAG_MASTER_SB_ONLY      0x200
++#define EXT2_FLAG_FORCE                       0x400
++#define EXT2_FLAG_SUPER_ONLY          0x800
++#define EXT2_FLAG_JOURNAL_DEV_OK      0x1000
++#define EXT2_FLAG_IMAGE_FILE          0x2000
++
++/*
++ * Special flag in the ext2 inode i_flag field that means that this is
++ * a new inode.  (So that ext2_write_inode() can clear extra fields.)
++ */
++#define EXT2_NEW_INODE_FL     0x80000000
++
++/*
++ * Flags for mkjournal
++ *
++ * EXT2_MKJOURNAL_V1_SUPER    Make a (deprecated) V1 journal superblock
++ */
++#define EXT2_MKJOURNAL_V1_SUPER       0x0000001
++
++struct struct_ext2_filsys {
++      errcode_t                       magic;
++      io_channel                      io;
++      int                             flags;
++      char *                          device_name;
++      struct ext2_super_block *       super;
++      unsigned int                    blocksize;
++      int                             fragsize;
++      dgrp_t                          group_desc_count;
++      unsigned long                   desc_blocks;
++      struct ext2_group_desc *        group_desc;
++      int                             inode_blocks_per_group;
++      ext2fs_inode_bitmap             inode_map;
++      ext2fs_block_bitmap             block_map;
++      errcode_t (*get_blocks)(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks);
++      errcode_t (*check_directory)(ext2_filsys fs, ext2_ino_t ino);
++      errcode_t (*write_bitmaps)(ext2_filsys fs);
++      errcode_t (*read_inode)(ext2_filsys fs, ext2_ino_t ino,
++                              struct ext2_inode *inode);
++      errcode_t (*write_inode)(ext2_filsys fs, ext2_ino_t ino,
++                              struct ext2_inode *inode);
++      ext2_badblocks_list             badblocks;
++      ext2_dblist                     dblist;
++      __u32                           stride; /* for mke2fs */
++      struct ext2_super_block *       orig_super;
++      struct ext2_image_hdr *         image_header;
++      __u32                           umask;
++      /*
++       * Reserved for future expansion
++       */
++      __u32                           reserved[8];
++
++      /*
++       * Reserved for the use of the calling application.
++       */
++      void *                          priv_data;
++
++      /*
++       * Inode cache
++       */
++      struct ext2_inode_cache         *icache;
++      io_channel                      image_io;
++};
++
++#if EXT2_FLAT_INCLUDES
++#include "e2_bitops.h"
++#else
++#include <ext2fs/bitops.h>
++#endif
++
++/*
++ * Return flags for the block iterator functions
++ */
++#define BLOCK_CHANGED 1
++#define BLOCK_ABORT   2
++#define BLOCK_ERROR   4
++
++/*
++ * Block interate flags
++ *
++ * BLOCK_FLAG_APPEND, or BLOCK_FLAG_HOLE, indicates that the interator
++ * function should be called on blocks where the block number is zero.
++ * This is used by ext2fs_expand_dir() to be able to add a new block
++ * to an inode.  It can also be used for programs that want to be able
++ * to deal with files that contain "holes".
++ * 
++ * BLOCK_FLAG_TRAVERSE indicates that the iterator function for the
++ * indirect, doubly indirect, etc. blocks should be called after all
++ * of the blocks containined in the indirect blocks are processed.
++ * This is useful if you are going to be deallocating blocks from an
++ * inode.
++ *
++ * BLOCK_FLAG_DATA_ONLY indicates that the iterator function should be
++ * called for data blocks only.
++ *
++ * BLOCK_FLAG_NO_LARGE is for internal use only.  It informs
++ * ext2fs_block_iterate2 that large files won't be accepted.
++ */
++#define BLOCK_FLAG_APPEND     1
++#define BLOCK_FLAG_HOLE               1
++#define BLOCK_FLAG_DEPTH_TRAVERSE     2
++#define BLOCK_FLAG_DATA_ONLY  4
++
++#define BLOCK_FLAG_NO_LARGE   0x1000
++
++/*
++ * Magic "block count" return values for the block iterator function.
++ */
++#define BLOCK_COUNT_IND               (-1)
++#define BLOCK_COUNT_DIND      (-2)
++#define BLOCK_COUNT_TIND      (-3)
++#define BLOCK_COUNT_TRANSLATOR        (-4)
++
++#if 0
++/*
++ * Flags for ext2fs_move_blocks
++ */
++#define EXT2_BMOVE_GET_DBLIST 0x0001  
++#define EXT2_BMOVE_DEBUG      0x0002
++#endif
++
++/*
++ * Flags for directory block reading and writing functions
++ */
++#define EXT2_DIRBLOCK_V2_STRUCT       0x0001
++
++/*
++ * Return flags for the directory iterator functions
++ */
++#define DIRENT_CHANGED        1
++#define DIRENT_ABORT  2
++#define DIRENT_ERROR  3
++
++/*
++ * Directory iterator flags
++ */
++
++#define DIRENT_FLAG_INCLUDE_EMPTY     1
++#define DIRENT_FLAG_INCLUDE_REMOVED   2
++
++#define DIRENT_DOT_FILE               1
++#define DIRENT_DOT_DOT_FILE   2
++#define DIRENT_OTHER_FILE     3
++#define DIRENT_DELETED_FILE   4
++
++/*
++ * Inode scan definitions
++ */
++typedef struct ext2_struct_inode_scan *ext2_inode_scan;
++
++/*
++ * ext2fs_scan flags
++ */
++#define EXT2_SF_CHK_BADBLOCKS 0x0001
++#define EXT2_SF_BAD_INODE_BLK 0x0002
++#define EXT2_SF_BAD_EXTRA_BYTES       0x0004
++#define EXT2_SF_SKIP_MISSING_ITABLE   0x0008
++
++/*
++ * ext2fs_check_if_mounted flags
++ */
++#define EXT2_MF_MOUNTED               1
++#define EXT2_MF_ISROOT                2
++#define EXT2_MF_READONLY      4
++#define EXT2_MF_SWAP          8
++
++/*
++ * Ext2/linux mode flags.  We define them here so that we don't need
++ * to depend on the OS's sys/stat.h, since we may be compiling on a
++ * non-Linux system.
++ */
++#define LINUX_S_IFMT  00170000
++#define LINUX_S_IFSOCK 0140000
++#define LINUX_S_IFLNK  0120000
++#define LINUX_S_IFREG  0100000
++#define LINUX_S_IFBLK  0060000
++#define LINUX_S_IFDIR  0040000
++#define LINUX_S_IFCHR  0020000
++#define LINUX_S_IFIFO  0010000
++#define LINUX_S_ISUID  0004000
++#define LINUX_S_ISGID  0002000
++#define LINUX_S_ISVTX  0001000
++
++#define LINUX_S_IRWXU 00700
++#define LINUX_S_IRUSR 00400
++#define LINUX_S_IWUSR 00200
++#define LINUX_S_IXUSR 00100
++
++#define LINUX_S_IRWXG 00070
++#define LINUX_S_IRGRP 00040
++#define LINUX_S_IWGRP 00020
++#define LINUX_S_IXGRP 00010
++
++#define LINUX_S_IRWXO 00007
++#define LINUX_S_IROTH 00004
++#define LINUX_S_IWOTH 00002
++#define LINUX_S_IXOTH 00001
++
++#define LINUX_S_ISLNK(m)      (((m) & LINUX_S_IFMT) == LINUX_S_IFLNK)
++#define LINUX_S_ISREG(m)      (((m) & LINUX_S_IFMT) == LINUX_S_IFREG)
++#define LINUX_S_ISDIR(m)      (((m) & LINUX_S_IFMT) == LINUX_S_IFDIR)
++#define LINUX_S_ISCHR(m)      (((m) & LINUX_S_IFMT) == LINUX_S_IFCHR)
++#define LINUX_S_ISBLK(m)      (((m) & LINUX_S_IFMT) == LINUX_S_IFBLK)
++#define LINUX_S_ISFIFO(m)     (((m) & LINUX_S_IFMT) == LINUX_S_IFIFO)
++#define LINUX_S_ISSOCK(m)     (((m) & LINUX_S_IFMT) == LINUX_S_IFSOCK)
++
++/*
++ * ext2 size of an inode
++ */
++#define EXT2_I_SIZE(i)        ((i)->i_size | ((__u64) (i)->i_size_high << 32))
++
++/*
++ * ext2_icount_t abstraction
++ */
++#define EXT2_ICOUNT_OPT_INCREMENT     0x01
++
++typedef struct ext2_icount *ext2_icount_t;
++
++/*
++ * Flags for ext2fs_bmap
++ */
++#define BMAP_ALLOC    0x0001
++#define BMAP_SET      0x0002
++
++/*
++ * Flags for imager.c functions
++ */
++#define IMAGER_FLAG_INODEMAP  1
++#define IMAGER_FLAG_SPARSEWRITE       2
++
++/*
++ * For checking structure magic numbers...
++ */
++
++#define EXT2_CHECK_MAGIC(struct, code) \
++        if ((struct)->magic != (code)) return (code)
++
++
++/*
++ * For ext2 compression support
++ */
++#define EXT2FS_COMPRESSED_BLKADDR ((blk_t) 0xffffffff)
++#define HOLE_BLKADDR(_b) ((_b) == 0 || (_b) == EXT2FS_COMPRESSED_BLKADDR)
++
++/*
++ * Features supported by this version of the library
++ */
++#define EXT2_LIB_FEATURE_COMPAT_SUPP  (EXT2_FEATURE_COMPAT_DIR_PREALLOC|\
++                                       EXT2_FEATURE_COMPAT_IMAGIC_INODES|\
++                                       EXT3_FEATURE_COMPAT_HAS_JOURNAL|\
++                                       EXT2_FEATURE_COMPAT_RESIZE_INODE|\
++                                       EXT2_FEATURE_COMPAT_DIR_INDEX|\
++                                       EXT2_FEATURE_COMPAT_EXT_ATTR)
++
++/* This #ifdef is temporary until compression is fully supported */
++#ifdef ENABLE_COMPRESSION
++#ifndef I_KNOW_THAT_COMPRESSION_IS_EXPERIMENTAL
++/* If the below warning bugs you, then have
++   `CPPFLAGS=-DI_KNOW_THAT_COMPRESSION_IS_EXPERIMENTAL' in your
++   environment at configure time. */
++ #warning "Compression support is experimental"
++#endif
++#define EXT2_LIB_FEATURE_INCOMPAT_SUPP        (EXT2_FEATURE_INCOMPAT_FILETYPE|\
++                                       EXT2_FEATURE_INCOMPAT_COMPRESSION|\
++                                       EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|\
++                                       EXT2_FEATURE_INCOMPAT_META_BG|\
++                                       EXT3_FEATURE_INCOMPAT_RECOVER)
++#else
++#define EXT2_LIB_FEATURE_INCOMPAT_SUPP        (EXT2_FEATURE_INCOMPAT_FILETYPE|\
++                                       EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|\
++                                       EXT2_FEATURE_INCOMPAT_META_BG|\
++                                       EXT3_FEATURE_INCOMPAT_RECOVER)
++#endif
++#define EXT2_LIB_FEATURE_RO_COMPAT_SUPP       (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|\
++                                       EXT2_FEATURE_RO_COMPAT_LARGE_FILE)
++/*
++ * function prototypes
++ */
++
++/* alloc.c */
++extern errcode_t ext2fs_new_inode(ext2_filsys fs, ext2_ino_t dir, int mode,
++                                ext2fs_inode_bitmap map, ext2_ino_t *ret);
++extern errcode_t ext2fs_new_block(ext2_filsys fs, blk_t goal,
++                                ext2fs_block_bitmap map, blk_t *ret);
++extern errcode_t ext2fs_get_free_blocks(ext2_filsys fs, blk_t start,
++                                      blk_t finish, int num,
++                                      ext2fs_block_bitmap map,
++                                      blk_t *ret);
++extern errcode_t ext2fs_alloc_block(ext2_filsys fs, blk_t goal,
++                                  char *block_buf, blk_t *ret);
++
++/* alloc_sb.c */
++extern int ext2fs_reserve_super_and_bgd(ext2_filsys fs, 
++                                      dgrp_t group,
++                                      ext2fs_block_bitmap bmap);
++
++/* alloc_stats.c */
++void ext2fs_inode_alloc_stats(ext2_filsys fs, ext2_ino_t ino, int inuse);
++void ext2fs_inode_alloc_stats2(ext2_filsys fs, ext2_ino_t ino,
++                             int inuse, int isdir);
++void ext2fs_block_alloc_stats(ext2_filsys fs, blk_t blk, int inuse);
++
++/* alloc_tables.c */
++extern errcode_t ext2fs_allocate_tables(ext2_filsys fs);
++extern errcode_t ext2fs_allocate_group_table(ext2_filsys fs, dgrp_t group,
++                                           ext2fs_block_bitmap bmap);
++
++/* badblocks.c */
++extern errcode_t ext2fs_u32_list_create(ext2_u32_list *ret, int size);
++extern errcode_t ext2fs_u32_list_add(ext2_u32_list bb, __u32 blk);
++extern int ext2fs_u32_list_find(ext2_u32_list bb, __u32 blk);
++extern int ext2fs_u32_list_test(ext2_u32_list bb, blk_t blk);
++extern errcode_t ext2fs_u32_list_iterate_begin(ext2_u32_list bb,
++                                             ext2_u32_iterate *ret);
++extern int ext2fs_u32_list_iterate(ext2_u32_iterate iter, blk_t *blk);
++extern void ext2fs_u32_list_iterate_end(ext2_u32_iterate iter);
++extern errcode_t ext2fs_u32_copy(ext2_u32_list src, ext2_u32_list *dest);
++extern int ext2fs_u32_list_equal(ext2_u32_list bb1, ext2_u32_list bb2);
++
++extern errcode_t ext2fs_badblocks_list_create(ext2_badblocks_list *ret,
++                                          int size);
++extern errcode_t ext2fs_badblocks_list_add(ext2_badblocks_list bb,
++                                         blk_t blk);
++extern int ext2fs_badblocks_list_test(ext2_badblocks_list bb,
++                                  blk_t blk);
++extern int ext2fs_u32_list_del(ext2_u32_list bb, __u32 blk);
++extern void ext2fs_badblocks_list_del(ext2_u32_list bb, __u32 blk);
++extern errcode_t
++      ext2fs_badblocks_list_iterate_begin(ext2_badblocks_list bb,
++                                          ext2_badblocks_iterate *ret);
++extern int ext2fs_badblocks_list_iterate(ext2_badblocks_iterate iter,
++                                       blk_t *blk);
++extern void ext2fs_badblocks_list_iterate_end(ext2_badblocks_iterate iter);
++extern errcode_t ext2fs_badblocks_copy(ext2_badblocks_list src,
++                                     ext2_badblocks_list *dest);
++extern int ext2fs_badblocks_equal(ext2_badblocks_list bb1,
++                                ext2_badblocks_list bb2);
++extern int ext2fs_u32_list_count(ext2_u32_list bb);
++
++/* bb_compat */
++extern errcode_t badblocks_list_create(badblocks_list *ret, int size);
++extern errcode_t badblocks_list_add(badblocks_list bb, blk_t blk);
++extern int badblocks_list_test(badblocks_list bb, blk_t blk);
++extern errcode_t badblocks_list_iterate_begin(badblocks_list bb,
++                                            badblocks_iterate *ret);
++extern int badblocks_list_iterate(badblocks_iterate iter, blk_t *blk);
++extern void badblocks_list_iterate_end(badblocks_iterate iter);
++extern void badblocks_list_free(badblocks_list bb);
++
++/* bb_inode.c */
++extern errcode_t ext2fs_update_bb_inode(ext2_filsys fs,
++                                      ext2_badblocks_list bb_list);
++
++/* bitmaps.c */
++extern errcode_t ext2fs_write_inode_bitmap(ext2_filsys fs);
++extern errcode_t ext2fs_write_block_bitmap (ext2_filsys fs);
++extern errcode_t ext2fs_read_inode_bitmap (ext2_filsys fs);
++extern errcode_t ext2fs_read_block_bitmap(ext2_filsys fs);
++extern errcode_t ext2fs_allocate_generic_bitmap(__u32 start,
++                                              __u32 end,
++                                              __u32 real_end,
++                                              const char *descr,
++                                              ext2fs_generic_bitmap *ret);
++extern errcode_t ext2fs_allocate_block_bitmap(ext2_filsys fs,
++                                            const char *descr,
++                                            ext2fs_block_bitmap *ret);
++extern errcode_t ext2fs_allocate_inode_bitmap(ext2_filsys fs,
++                                            const char *descr,
++                                            ext2fs_inode_bitmap *ret);
++extern errcode_t ext2fs_fudge_inode_bitmap_end(ext2fs_inode_bitmap bitmap,
++                                             ext2_ino_t end, ext2_ino_t *oend);
++extern errcode_t ext2fs_fudge_block_bitmap_end(ext2fs_block_bitmap bitmap,
++                                             blk_t end, blk_t *oend);
++extern void ext2fs_clear_inode_bitmap(ext2fs_inode_bitmap bitmap);
++extern void ext2fs_clear_block_bitmap(ext2fs_block_bitmap bitmap);
++extern errcode_t ext2fs_read_bitmaps(ext2_filsys fs);
++extern errcode_t ext2fs_write_bitmaps(ext2_filsys fs);
++
++/* block.c */
++extern errcode_t ext2fs_block_iterate(ext2_filsys fs,
++                                    ext2_ino_t        ino,
++                                    int       flags,
++                                    char *block_buf,
++                                    int (*func)(ext2_filsys fs,
++                                                blk_t *blocknr,
++                                                int   blockcnt,
++                                                void  *priv_data),
++                                    void *priv_data);
++errcode_t ext2fs_block_iterate2(ext2_filsys fs,
++                              ext2_ino_t      ino,
++                              int     flags,
++                              char *block_buf,
++                              int (*func)(ext2_filsys fs,
++                                          blk_t       *blocknr,
++                                          e2_blkcnt_t blockcnt,
++                                          blk_t       ref_blk,
++                                          int         ref_offset,
++                                          void        *priv_data),
++                              void *priv_data);
++
++/* bmap.c */
++extern errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino,
++                           struct ext2_inode *inode, 
++                           char *block_buf, int bmap_flags,
++                           blk_t block, blk_t *phys_blk);
++
++
++#if 0
++/* bmove.c */
++extern errcode_t ext2fs_move_blocks(ext2_filsys fs,
++                                  ext2fs_block_bitmap reserve,
++                                  ext2fs_block_bitmap alloc_map,
++                                  int flags);
++#endif
++
++/* check_desc.c */
++extern errcode_t ext2fs_check_desc(ext2_filsys fs);
++
++/* closefs.c */
++extern errcode_t ext2fs_close(ext2_filsys fs);
++extern errcode_t ext2fs_flush(ext2_filsys fs);
++extern int ext2fs_bg_has_super(ext2_filsys fs, int group_block);
++extern int ext2fs_super_and_bgd_loc(ext2_filsys fs, 
++                                  dgrp_t group,
++                                  blk_t *ret_super_blk,
++                                  blk_t *ret_old_desc_blk,
++                                  blk_t *ret_new_desc_blk,
++                                  int *ret_meta_bg);
++extern void ext2fs_update_dynamic_rev(ext2_filsys fs);
++
++/* cmp_bitmaps.c */
++extern errcode_t ext2fs_compare_block_bitmap(ext2fs_block_bitmap bm1,
++                                           ext2fs_block_bitmap bm2);
++extern errcode_t ext2fs_compare_inode_bitmap(ext2fs_inode_bitmap bm1,
++                                           ext2fs_inode_bitmap bm2);
++
++/* dblist.c */
++
++extern errcode_t ext2fs_get_num_dirs(ext2_filsys fs, ext2_ino_t *ret_num_dirs);
++extern errcode_t ext2fs_init_dblist(ext2_filsys fs, ext2_dblist *ret_dblist);
++extern errcode_t ext2fs_add_dir_block(ext2_dblist dblist, ext2_ino_t ino,
++                                    blk_t blk, int blockcnt);
++extern void ext2fs_dblist_sort(ext2_dblist dblist,
++                             EXT2_QSORT_TYPE (*sortfunc)(const void *,
++                                                         const void *));
++extern errcode_t ext2fs_dblist_iterate(ext2_dblist dblist,
++      int (*func)(ext2_filsys fs, struct ext2_db_entry *db_info,
++                  void        *priv_data),
++       void *priv_data);
++extern errcode_t ext2fs_set_dir_block(ext2_dblist dblist, ext2_ino_t ino,
++                                    blk_t blk, int blockcnt);
++extern errcode_t ext2fs_copy_dblist(ext2_dblist src,
++                                  ext2_dblist *dest);
++extern int ext2fs_dblist_count(ext2_dblist dblist);
++
++/* dblist_dir.c */
++extern errcode_t
++      ext2fs_dblist_dir_iterate(ext2_dblist dblist,
++                                int   flags,
++                                char  *block_buf,
++                                int (*func)(ext2_ino_t        dir,
++                                            int               entry,
++                                            struct ext2_dir_entry *dirent,
++                                            int       offset,
++                                            int       blocksize,
++                                            char      *buf,
++                                            void      *priv_data),
++                                void *priv_data);
++
++/* dirblock.c */
++extern errcode_t ext2fs_read_dir_block(ext2_filsys fs, blk_t block,
++                                     void *buf);
++extern errcode_t ext2fs_read_dir_block2(ext2_filsys fs, blk_t block,
++                                      void *buf, int flags);
++extern errcode_t ext2fs_write_dir_block(ext2_filsys fs, blk_t block,
++                                      void *buf);
++extern errcode_t ext2fs_write_dir_block2(ext2_filsys fs, blk_t block,
++                                       void *buf, int flags);
++
++/* dirhash.c */
++extern errcode_t ext2fs_dirhash(int version, const char *name, int len,
++                              const __u32 *seed,
++                              ext2_dirhash_t *ret_hash,
++                              ext2_dirhash_t *ret_minor_hash);
++
++
++/* dir_iterate.c */
++extern errcode_t ext2fs_dir_iterate(ext2_filsys fs, 
++                            ext2_ino_t dir,
++                            int flags,
++                            char *block_buf,
++                            int (*func)(struct ext2_dir_entry *dirent,
++                                        int   offset,
++                                        int   blocksize,
++                                        char  *buf,
++                                        void  *priv_data),
++                            void *priv_data);
++extern errcode_t ext2fs_dir_iterate2(ext2_filsys fs, 
++                            ext2_ino_t dir,
++                            int flags,
++                            char *block_buf,
++                            int (*func)(ext2_ino_t    dir,
++                                        int   entry,
++                                        struct ext2_dir_entry *dirent,
++                                        int   offset,
++                                        int   blocksize,
++                                        char  *buf,
++                                        void  *priv_data),
++                            void *priv_data);
++
++/* dupfs.c */
++extern errcode_t ext2fs_dup_handle(ext2_filsys src, ext2_filsys *dest);
++
++/* expanddir.c */
++extern errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir);
++
++/* ext_attr.c */
++extern errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf);
++extern errcode_t ext2fs_write_ext_attr(ext2_filsys fs, blk_t block,
++                                     void *buf);
++extern errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk,
++                                         char *block_buf,
++                                         int adjust, __u32 *newcount);
++
++/* fileio.c */
++extern errcode_t ext2fs_file_open2(ext2_filsys fs, ext2_ino_t ino,
++                                 struct ext2_inode *inode,
++                                 int flags, ext2_file_t *ret);
++extern errcode_t ext2fs_file_open(ext2_filsys fs, ext2_ino_t ino,
++                                int flags, ext2_file_t *ret);
++extern ext2_filsys ext2fs_file_get_fs(ext2_file_t file);
++extern errcode_t ext2fs_file_close(ext2_file_t file);
++extern errcode_t ext2fs_file_flush(ext2_file_t file);
++extern errcode_t ext2fs_file_read(ext2_file_t file, void *buf,
++                                unsigned int wanted, unsigned int *got);
++extern errcode_t ext2fs_file_write(ext2_file_t file, const void *buf,
++                                 unsigned int nbytes, unsigned int *written);
++extern errcode_t ext2fs_file_llseek(ext2_file_t file, __u64 offset,
++                                 int whence, __u64 *ret_pos);
++extern errcode_t ext2fs_file_lseek(ext2_file_t file, ext2_off_t offset,
++                                 int whence, ext2_off_t *ret_pos);
++errcode_t ext2fs_file_get_lsize(ext2_file_t file, __u64 *ret_size);
++extern ext2_off_t ext2fs_file_get_size(ext2_file_t file);
++extern errcode_t ext2fs_file_set_size(ext2_file_t file, ext2_off_t size);
++
++/* finddev.c */
++extern char *ext2fs_find_block_device(dev_t device);
++
++/* flushb.c */
++extern errcode_t ext2fs_sync_device(int fd, int flushb);
++
++/* freefs.c */
++extern void ext2fs_free(ext2_filsys fs);
++extern void ext2fs_free_generic_bitmap(ext2fs_inode_bitmap bitmap);
++extern void ext2fs_free_block_bitmap(ext2fs_block_bitmap bitmap);
++extern void ext2fs_free_inode_bitmap(ext2fs_inode_bitmap bitmap);
++extern void ext2fs_free_dblist(ext2_dblist dblist);
++extern void ext2fs_badblocks_list_free(ext2_badblocks_list bb);
++extern void ext2fs_u32_list_free(ext2_u32_list bb);
++
++/* getsize.c */
++extern errcode_t ext2fs_get_device_size(const char *file, int blocksize,
++                                      blk_t *retblocks);
++
++/* getsectsize.c */
++errcode_t ext2fs_get_device_sectsize(const char *file, int *sectsize);
++
++/* imager.c */
++extern errcode_t ext2fs_image_inode_write(ext2_filsys fs, int fd, int flags);
++extern errcode_t ext2fs_image_inode_read(ext2_filsys fs, int fd, int flags);
++extern errcode_t ext2fs_image_super_write(ext2_filsys fs, int fd, int flags);
++extern errcode_t ext2fs_image_super_read(ext2_filsys fs, int fd, int flags);
++extern errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags);
++extern errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags);
++
++/* ind_block.c */
++errcode_t ext2fs_read_ind_block(ext2_filsys fs, blk_t blk, void *buf);
++errcode_t ext2fs_write_ind_block(ext2_filsys fs, blk_t blk, void *buf);
++
++/* initialize.c */
++extern errcode_t ext2fs_initialize(const char *name, int flags,
++                                 struct ext2_super_block *param,
++                                 io_manager manager, ext2_filsys *ret_fs);
++
++/* icount.c */
++extern void ext2fs_free_icount(ext2_icount_t icount);
++extern errcode_t ext2fs_create_icount2(ext2_filsys fs, int flags, 
++                                     unsigned int size,
++                                     ext2_icount_t hint, ext2_icount_t *ret);
++extern errcode_t ext2fs_create_icount(ext2_filsys fs, int flags, 
++                                    unsigned int size,
++                                    ext2_icount_t *ret);
++extern errcode_t ext2fs_icount_fetch(ext2_icount_t icount, ext2_ino_t ino,
++                                   __u16 *ret);
++extern errcode_t ext2fs_icount_increment(ext2_icount_t icount, ext2_ino_t ino,
++                                       __u16 *ret);
++extern errcode_t ext2fs_icount_decrement(ext2_icount_t icount, ext2_ino_t ino,
++                                       __u16 *ret);
++extern errcode_t ext2fs_icount_store(ext2_icount_t icount, ext2_ino_t ino,
++                                   __u16 count);
++extern ext2_ino_t ext2fs_get_icount_size(ext2_icount_t icount);
++errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *);
++
++/* inode.c */
++extern errcode_t ext2fs_flush_icache(ext2_filsys fs);
++extern errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, 
++                                          ext2_ino_t *ino,
++                                          struct ext2_inode *inode, 
++                                          int bufsize);
++extern errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks,
++                                ext2_inode_scan *ret_scan);
++extern void ext2fs_close_inode_scan(ext2_inode_scan scan);
++extern errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ext2_ino_t *ino,
++                             struct ext2_inode *inode);
++extern errcode_t ext2fs_inode_scan_goto_blockgroup(ext2_inode_scan scan,
++                                                 int  group);
++extern void ext2fs_set_inode_callback
++      (ext2_inode_scan scan,
++       errcode_t (*done_group)(ext2_filsys fs,
++                               ext2_inode_scan scan,
++                               dgrp_t group,
++                               void * priv_data),
++       void *done_group_data);
++extern int ext2fs_inode_scan_flags(ext2_inode_scan scan, int set_flags,
++                                 int clear_flags);
++extern errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
++                                      struct ext2_inode * inode, 
++                                      int bufsize);
++extern errcode_t ext2fs_read_inode (ext2_filsys fs, ext2_ino_t ino,
++                          struct ext2_inode * inode);
++extern errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
++                                       struct ext2_inode * inode, 
++                                       int bufsize);
++extern errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino,
++                          struct ext2_inode * inode);
++extern errcode_t ext2fs_write_new_inode(ext2_filsys fs, ext2_ino_t ino,
++                          struct ext2_inode * inode);
++extern errcode_t ext2fs_get_blocks(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks);
++extern errcode_t ext2fs_check_directory(ext2_filsys fs, ext2_ino_t ino);
++
++/* inode_io.c */
++extern io_manager inode_io_manager;
++extern errcode_t ext2fs_inode_io_intern(ext2_filsys fs, ext2_ino_t ino, 
++                                      char **name);
++extern errcode_t ext2fs_inode_io_intern2(ext2_filsys fs, ext2_ino_t ino,
++                                       struct ext2_inode *inode,
++                                       char **name);
++      
++/* ismounted.c */
++extern errcode_t ext2fs_check_if_mounted(const char *file, int *mount_flags);
++extern errcode_t ext2fs_check_mount_point(const char *device, int *mount_flags,
++                                        char *mtpt, int mtlen);
++
++/* namei.c */
++extern errcode_t ext2fs_lookup(ext2_filsys fs, ext2_ino_t dir, const char *name,
++                       int namelen, char *buf, ext2_ino_t *inode);
++extern errcode_t ext2fs_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
++                      const char *name, ext2_ino_t *inode);
++errcode_t ext2fs_namei_follow(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
++                            const char *name, ext2_ino_t *inode);
++extern errcode_t ext2fs_follow_link(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
++                      ext2_ino_t inode, ext2_ino_t *res_inode);
++
++/* native.c */
++int ext2fs_native_flag(void);
++
++/* newdir.c */
++extern errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino,
++                              ext2_ino_t parent_ino, char **block);
++
++/* mkdir.c */
++extern errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
++                            const char *name);
++
++/* mkjournal.c */
++extern errcode_t ext2fs_create_journal_superblock(ext2_filsys fs,
++                                                __u32 size, int flags,
++                                                char  **ret_jsb);
++extern errcode_t ext2fs_add_journal_device(ext2_filsys fs,
++                                         ext2_filsys journal_dev);
++extern errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t size,
++                                        int flags);
++
++/* openfs.c */
++extern errcode_t ext2fs_open(const char *name, int flags, int superblock,
++                           unsigned int block_size, io_manager manager,
++                           ext2_filsys *ret_fs);
++extern errcode_t ext2fs_open2(const char *name, const char *io_options, 
++                            int flags, int superblock, 
++                            unsigned int block_size, io_manager manager,
++                            ext2_filsys *ret_fs);
++extern blk_t ext2fs_descriptor_block_loc(ext2_filsys fs, blk_t group_block, 
++                                       dgrp_t i);
++errcode_t ext2fs_get_data_io(ext2_filsys fs, io_channel *old_io);
++errcode_t ext2fs_set_data_io(ext2_filsys fs, io_channel new_io);
++errcode_t ext2fs_rewrite_to_io(ext2_filsys fs, io_channel new_io);
++
++/* get_pathname.c */
++extern errcode_t ext2fs_get_pathname(ext2_filsys fs, ext2_ino_t dir, ext2_ino_t ino,
++                             char **name);
++
++/* link.c */
++errcode_t ext2fs_link(ext2_filsys fs, ext2_ino_t dir, const char *name,
++                    ext2_ino_t ino, int flags);
++errcode_t ext2fs_unlink(ext2_filsys fs, ext2_ino_t dir, const char *name,
++                      ext2_ino_t ino, int flags);
++
++/* read_bb.c */
++extern errcode_t ext2fs_read_bb_inode(ext2_filsys fs,
++                                    ext2_badblocks_list *bb_list);
++
++/* read_bb_file.c */
++extern errcode_t ext2fs_read_bb_FILE2(ext2_filsys fs, FILE *f, 
++                                    ext2_badblocks_list *bb_list,
++                                    void *priv_data,
++                                    void (*invalid)(ext2_filsys fs,
++                                                    blk_t blk,
++                                                    char *badstr,
++                                                    void *priv_data));
++extern errcode_t ext2fs_read_bb_FILE(ext2_filsys fs, FILE *f, 
++                                   ext2_badblocks_list *bb_list,
++                                   void (*invalid)(ext2_filsys fs,
++                                                   blk_t blk));
++
++/* res_gdt.c */
++extern errcode_t ext2fs_create_resize_inode(ext2_filsys fs);
++
++/* rs_bitmap.c */
++extern errcode_t ext2fs_resize_generic_bitmap(__u32 new_end,
++                                            __u32 new_real_end,
++                                            ext2fs_generic_bitmap bmap);
++extern errcode_t ext2fs_resize_inode_bitmap(__u32 new_end, __u32 new_real_end,
++                                          ext2fs_inode_bitmap bmap);
++extern errcode_t ext2fs_resize_block_bitmap(__u32 new_end, __u32 new_real_end,
++                                          ext2fs_block_bitmap bmap);
++extern errcode_t ext2fs_copy_bitmap(ext2fs_generic_bitmap src,
++                                  ext2fs_generic_bitmap *dest);
++
++/* swapfs.c */
++extern void ext2fs_swap_ext_attr(char *to, char *from, int bufsize, 
++                               int has_header);
++extern void ext2fs_swap_super(struct ext2_super_block * super);
++extern void ext2fs_swap_group_desc(struct ext2_group_desc *gdp);
++extern void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t,
++                                 struct ext2_inode_large *f, int hostorder,
++                                 int bufsize);
++extern void ext2fs_swap_inode(ext2_filsys fs,struct ext2_inode *t,
++                            struct ext2_inode *f, int hostorder);
++
++/* valid_blk.c */
++extern int ext2fs_inode_has_valid_blocks(struct ext2_inode *inode);
++
++/* version.c */
++extern int ext2fs_parse_version_string(const char *ver_string);
++extern int ext2fs_get_library_version(const char **ver_string,
++                                    const char **date_string);
++
++/* write_bb_file.c */
++extern errcode_t ext2fs_write_bb_FILE(ext2_badblocks_list bb_list,
++                                    unsigned int flags,
++                                    FILE *f);
++
++
++/* inline functions */
++extern errcode_t ext2fs_get_mem(unsigned long size, void *ptr);
++extern errcode_t ext2fs_free_mem(void *ptr);
++extern errcode_t ext2fs_resize_mem(unsigned long old_size,
++                                 unsigned long size, void *ptr);
++extern void ext2fs_mark_super_dirty(ext2_filsys fs);
++extern void ext2fs_mark_changed(ext2_filsys fs);
++extern int ext2fs_test_changed(ext2_filsys fs);
++extern void ext2fs_mark_valid(ext2_filsys fs);
++extern void ext2fs_unmark_valid(ext2_filsys fs);
++extern int ext2fs_test_valid(ext2_filsys fs);
++extern void ext2fs_mark_ib_dirty(ext2_filsys fs);
++extern void ext2fs_mark_bb_dirty(ext2_filsys fs);
++extern int ext2fs_test_ib_dirty(ext2_filsys fs);
++extern int ext2fs_test_bb_dirty(ext2_filsys fs);
++extern int ext2fs_group_of_blk(ext2_filsys fs, blk_t blk);
++extern int ext2fs_group_of_ino(ext2_filsys fs, ext2_ino_t ino);
++extern blk_t ext2fs_inode_data_blocks(ext2_filsys fs,
++                                    struct ext2_inode *inode);
++
++/*
++ * The actual inlined functions definitions themselves...
++ *
++ * If NO_INLINE_FUNCS is defined, then we won't try to do inline
++ * functions at all!
++ */
++#if (defined(INCLUDE_INLINE_FUNCS) || !defined(NO_INLINE_FUNCS))
++#ifdef INCLUDE_INLINE_FUNCS
++#define _INLINE_ extern
++#else
++#ifdef __GNUC__
++#define _INLINE_ extern __inline__
++#else                         /* For Watcom C */
++#define _INLINE_ extern inline
++#endif
++#endif
++
++#ifndef EXT2_CUSTOM_MEMORY_ROUTINES
++/*
++ *  Allocate memory
++ */
++_INLINE_ errcode_t ext2fs_get_mem(unsigned long size, void *ptr)
++{
++      void **pp = (void **)ptr;
++
++      *pp = malloc(size);
++      if (!*pp)
++              return EXT2_ET_NO_MEMORY;
++      return 0;
++}
++
++/*
++ * Free memory
++ */
++_INLINE_ errcode_t ext2fs_free_mem(void *ptr)
++{
++      void **pp = (void **)ptr;
++
++      free(*pp);
++      *pp = 0;
++      return 0;
++}
++      
++/*
++ *  Resize memory
++ */
++_INLINE_ errcode_t ext2fs_resize_mem(unsigned long EXT2FS_ATTR((unused)) old_size,
++                                   unsigned long size, void *ptr)
++{
++      void *p;
++      void **pp = (void **)ptr;
++
++      p = realloc(*pp, size);
++      if (!p)
++              return EXT2_ET_NO_MEMORY;
++      *pp = p;
++      return 0;
++}
++#endif        /* Custom memory routines */
++
++/*
++ * Mark a filesystem superblock as dirty
++ */
++_INLINE_ void ext2fs_mark_super_dirty(ext2_filsys fs)
++{
++      fs->flags |= EXT2_FLAG_DIRTY | EXT2_FLAG_CHANGED;
++}
++
++/*
++ * Mark a filesystem as changed
++ */
++_INLINE_ void ext2fs_mark_changed(ext2_filsys fs)
++{
++      fs->flags |= EXT2_FLAG_CHANGED;
++}
++
++/*
++ * Check to see if a filesystem has changed
++ */
++_INLINE_ int ext2fs_test_changed(ext2_filsys fs)
++{
++      return (fs->flags & EXT2_FLAG_CHANGED);
++}
++
++/*
++ * Mark a filesystem as valid
++ */
++_INLINE_ void ext2fs_mark_valid(ext2_filsys fs)
++{
++      fs->flags |= EXT2_FLAG_VALID;
++}
++
++/*
++ * Mark a filesystem as NOT valid
++ */
++_INLINE_ void ext2fs_unmark_valid(ext2_filsys fs)
++{
++      fs->flags &= ~EXT2_FLAG_VALID;
++}
++
++/*
++ * Check to see if a filesystem is valid
++ */
++_INLINE_ int ext2fs_test_valid(ext2_filsys fs)
++{
++      return (fs->flags & EXT2_FLAG_VALID);
++}
++
++/*
++ * Mark the inode bitmap as dirty
++ */
++_INLINE_ void ext2fs_mark_ib_dirty(ext2_filsys fs)
++{
++      fs->flags |= EXT2_FLAG_IB_DIRTY | EXT2_FLAG_CHANGED;
++}
++
++/*
++ * Mark the block bitmap as dirty
++ */
++_INLINE_ void ext2fs_mark_bb_dirty(ext2_filsys fs)
++{
++      fs->flags |= EXT2_FLAG_BB_DIRTY | EXT2_FLAG_CHANGED;
++}
++
++/*
++ * Check to see if a filesystem's inode bitmap is dirty
++ */
++_INLINE_ int ext2fs_test_ib_dirty(ext2_filsys fs)
++{
++      return (fs->flags & EXT2_FLAG_IB_DIRTY);
++}
++
++/*
++ * Check to see if a filesystem's block bitmap is dirty
++ */
++_INLINE_ int ext2fs_test_bb_dirty(ext2_filsys fs)
++{
++      return (fs->flags & EXT2_FLAG_BB_DIRTY);
++}
++
++/*
++ * Return the group # of a block
++ */
++_INLINE_ int ext2fs_group_of_blk(ext2_filsys fs, blk_t blk)
++{
++      return (blk - fs->super->s_first_data_block) /
++              fs->super->s_blocks_per_group;
++}
++
++/*
++ * Return the group # of an inode number
++ */
++_INLINE_ int ext2fs_group_of_ino(ext2_filsys fs, ext2_ino_t ino)
++{
++      return (ino - 1) / fs->super->s_inodes_per_group;
++}
++
++_INLINE_ blk_t ext2fs_inode_data_blocks(ext2_filsys fs,
++                                      struct ext2_inode *inode)
++{
++       return inode->i_blocks -
++              (inode->i_file_acl ? fs->blocksize >> 9 : 0);
++}
++#undef _INLINE_
++#endif
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _EXT2FS_EXT2FS_H */
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/ext2fsP.h busybox/e2fsprogs/ext2fs/ext2fsP.h
+--- busybox-1.00/e2fsprogs/ext2fs/ext2fsP.h    1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/ext2fsP.h 2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,88 @@
++/*
++ * ext2fsP.h --- private header file for ext2 library
++ * 
++ * Copyright (C) 1997 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include "ext2fs.h"
++
++/*
++ * Badblocks list
++ */
++struct ext2_struct_u32_list {
++      int     magic;
++      int     num;
++      int     size;
++      __u32   *list;
++      int     badblocks_flags;
++};
++
++struct ext2_struct_u32_iterate {
++      int                     magic;
++      ext2_u32_list           bb;
++      int                     ptr;
++};
++
++
++/*
++ * Directory block iterator definition
++ */
++struct ext2_struct_dblist {
++      int                     magic;
++      ext2_filsys             fs;
++      ext2_ino_t              size;
++      ext2_ino_t              count;
++      int                     sorted;
++      struct ext2_db_entry *  list;
++};
++
++/*
++ * For directory iterators
++ */
++struct dir_context {
++      ext2_ino_t              dir;
++      int             flags;
++      char            *buf;
++      int (*func)(ext2_ino_t  dir,
++                  int entry,
++                  struct ext2_dir_entry *dirent,
++                  int offset,
++                  int blocksize,
++                  char        *buf,
++                  void        *priv_data);
++      void            *priv_data;
++      errcode_t       errcode;
++};
++
++/*
++ * Inode cache structure
++ */
++struct ext2_inode_cache {
++      void *                          buffer;
++      blk_t                           buffer_blk;
++      int                             cache_last;
++      int                             cache_size;
++      int                             refcount;
++      struct ext2_inode_cache_ent     *cache;
++};
++
++struct ext2_inode_cache_ent {
++      ext2_ino_t              ino;
++      struct ext2_inode       inode;
++};
++
++/* Function prototypes */
++
++extern int ext2fs_process_dir_block(ext2_filsys       fs,
++                                  blk_t               *blocknr,
++                                  e2_blkcnt_t         blockcnt,
++                                  blk_t               ref_block,
++                                  int                 ref_offset,
++                                  void                *priv_data);
++
++
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/ext_attr.c busybox/e2fsprogs/ext2fs/ext_attr.c
+--- busybox-1.00/e2fsprogs/ext2fs/ext_attr.c   1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/ext_attr.c        2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,105 @@
++/*
++ * ext_attr.c --- extended attribute blocks
++ * 
++ * Copyright (C) 2001 Andreas Gruenbacher, <a.gruenbacher@computer.org>
++ *
++ * Copyright (C) 2002 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <string.h>
++#include <time.h>
++
++#include "ext2_fs.h"
++#include "ext2_ext_attr.h"
++
++#include "ext2fs.h"
++
++errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf)
++{
++      errcode_t       retval;
++
++      retval = io_channel_read_blk(fs->io, block, 1, buf);
++      if (retval)
++              return retval;
++#ifdef EXT2FS_ENABLE_SWAPFS
++      if ((fs->flags & (EXT2_FLAG_SWAP_BYTES|
++                        EXT2_FLAG_SWAP_BYTES_READ)) != 0)
++              ext2fs_swap_ext_attr(buf, buf, fs->blocksize, 1);
++#endif
++      return 0;
++}
++
++errcode_t ext2fs_write_ext_attr(ext2_filsys fs, blk_t block, void *inbuf)
++{
++      errcode_t       retval;
++      char            *write_buf;
++      char            *buf = NULL;
++
++#ifdef EXT2FS_ENABLE_SWAPFS
++      if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
++          (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)) {
++              retval = ext2fs_get_mem(fs->blocksize, &buf);
++              if (retval)
++                      return retval;
++              write_buf = buf;
++              ext2fs_swap_ext_attr(buf, inbuf, fs->blocksize, 1);
++      } else
++#endif
++              write_buf = (char *) inbuf;
++      retval = io_channel_write_blk(fs->io, block, 1, write_buf);
++      if (buf)
++              ext2fs_free_mem(&buf);
++      if (!retval)
++              ext2fs_mark_changed(fs);
++      return retval;
++}
++
++/*
++ * This function adjusts the reference count of the EA block.
++ */
++errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk,
++                                  char *block_buf, int adjust,
++                                  __u32 *newcount)
++{
++      errcode_t       retval;
++      struct ext2_ext_attr_header *header;
++      char    *buf = 0;
++
++      if ((blk >= fs->super->s_blocks_count) ||
++          (blk < fs->super->s_first_data_block))
++              return EXT2_ET_BAD_EA_BLOCK_NUM;
++
++      if (!block_buf) {
++              retval = ext2fs_get_mem(fs->blocksize, &buf);
++              if (retval)
++                      return retval;
++              block_buf = buf;
++      }
++
++      retval = ext2fs_read_ext_attr(fs, blk, block_buf);
++      if (retval)
++              goto errout;
++
++      header = (struct ext2_ext_attr_header *) block_buf;
++      header->h_refcount += adjust;
++      if (newcount)
++              *newcount = header->h_refcount;
++
++      retval = ext2fs_write_ext_attr(fs, blk, block_buf);
++      if (retval)
++              goto errout;
++
++errout:
++      if (buf)
++              ext2fs_free_mem(&buf);
++      return retval;
++}
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/fileio.c busybox/e2fsprogs/ext2fs/fileio.c
+--- busybox-1.00/e2fsprogs/ext2fs/fileio.c     1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/fileio.c  2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,378 @@
++/*
++ * fileio.c --- Simple file I/O routines
++ * 
++ * Copyright (C) 1997 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++struct ext2_file {
++      errcode_t               magic;
++      ext2_filsys             fs;
++      ext2_ino_t              ino;
++      struct ext2_inode       inode;
++      int                     flags;
++      __u64                   pos;
++      blk_t                   blockno;
++      blk_t                   physblock;
++      char                    *buf;
++};
++
++#define BMAP_BUFFER (file->buf + fs->blocksize)
++
++errcode_t ext2fs_file_open2(ext2_filsys fs, ext2_ino_t ino,
++                          struct ext2_inode *inode,
++                          int flags, ext2_file_t *ret)
++{
++      ext2_file_t     file;
++      errcode_t       retval;
++
++      /*
++       * Don't let caller create or open a file for writing if the
++       * filesystem is read-only.
++       */
++      if ((flags & (EXT2_FILE_WRITE | EXT2_FILE_CREATE)) &&
++          !(fs->flags & EXT2_FLAG_RW))
++              return EXT2_ET_RO_FILSYS;
++
++      retval = ext2fs_get_mem(sizeof(struct ext2_file), &file);
++      if (retval)
++              return retval;
++      
++      memset(file, 0, sizeof(struct ext2_file));
++      file->magic = EXT2_ET_MAGIC_EXT2_FILE;
++      file->fs = fs;
++      file->ino = ino;
++      file->flags = flags & EXT2_FILE_MASK;
++
++      if (inode) {
++              memcpy(&file->inode, inode, sizeof(struct ext2_inode));
++      } else {
++              retval = ext2fs_read_inode(fs, ino, &file->inode);
++              if (retval)
++                      goto fail;
++      }
++      
++      retval = ext2fs_get_mem(fs->blocksize * 3, &file->buf);
++      if (retval)
++              goto fail;
++
++      *ret = file;
++      return 0;
++      
++fail:
++      if (file->buf)
++              ext2fs_free_mem(&file->buf);
++      ext2fs_free_mem(&file);
++      return retval;
++}
++
++errcode_t ext2fs_file_open(ext2_filsys fs, ext2_ino_t ino,
++                         int flags, ext2_file_t *ret)
++{
++      return ext2fs_file_open2(fs, ino, NULL, flags, ret);
++}
++
++/*
++ * This function returns the filesystem handle of a file from the structure
++ */
++ext2_filsys ext2fs_file_get_fs(ext2_file_t file)
++{
++      if (file->magic != EXT2_ET_MAGIC_EXT2_FILE)
++              return 0;
++      return file->fs;
++}
++
++/*
++ * This function flushes the dirty block buffer out to disk if
++ * necessary.
++ */
++errcode_t ext2fs_file_flush(ext2_file_t file)
++{
++      errcode_t       retval;
++      ext2_filsys fs;
++      
++      EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
++      fs = file->fs;
++
++      if (!(file->flags & EXT2_FILE_BUF_VALID) ||
++          !(file->flags & EXT2_FILE_BUF_DIRTY))
++              return 0;
++
++      /*
++       * OK, the physical block hasn't been allocated yet.
++       * Allocate it.
++       */
++      if (!file->physblock) {
++              retval = ext2fs_bmap(fs, file->ino, &file->inode,
++                                   BMAP_BUFFER, file->ino ? BMAP_ALLOC : 0,
++                                   file->blockno, &file->physblock);
++              if (retval)
++                      return retval;
++      }
++
++      retval = io_channel_write_blk(fs->io, file->physblock,
++                                    1, file->buf);
++      if (retval)
++              return retval;
++
++      file->flags &= ~EXT2_FILE_BUF_DIRTY;
++
++      return retval;
++}
++
++/*
++ * This function synchronizes the file's block buffer and the current
++ * file position, possibly invalidating block buffer if necessary
++ */
++static errcode_t sync_buffer_position(ext2_file_t file)
++{
++      blk_t   b;
++      errcode_t       retval;
++
++      b = file->pos / file->fs->blocksize;
++      if (b != file->blockno) {
++              retval = ext2fs_file_flush(file);
++              if (retval)
++                      return retval;
++              file->flags &= ~EXT2_FILE_BUF_VALID;
++      }
++      file->blockno = b;
++      return 0;
++}
++
++/*
++ * This function loads the file's block buffer with valid data from
++ * the disk as necessary.
++ *
++ * If dontfill is true, then skip initializing the buffer since we're
++ * going to be replacing its entire contents anyway.  If set, then the
++ * function basically only sets file->physblock and EXT2_FILE_BUF_VALID
++ */
++#define DONTFILL 1
++static errcode_t load_buffer(ext2_file_t file, int dontfill)
++{
++      ext2_filsys     fs = file->fs;
++      errcode_t       retval;
++
++      if (!(file->flags & EXT2_FILE_BUF_VALID)) {
++              retval = ext2fs_bmap(fs, file->ino, &file->inode,
++                                   BMAP_BUFFER, 0, file->blockno,
++                                   &file->physblock);
++              if (retval)
++                      return retval;
++              if (!dontfill) {
++                      if (file->physblock) {
++                              retval = io_channel_read_blk(fs->io,
++                                                           file->physblock, 
++                                                           1, file->buf);
++                              if (retval)
++                                      return retval;
++                      } else
++                              memset(file->buf, 0, fs->blocksize);
++              }
++              file->flags |= EXT2_FILE_BUF_VALID;
++      }
++      return 0;
++}
++      
++
++errcode_t ext2fs_file_close(ext2_file_t file)
++{
++      errcode_t       retval;
++      
++      EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
++
++      retval = ext2fs_file_flush(file);
++      
++      if (file->buf)
++              ext2fs_free_mem(&file->buf);
++      ext2fs_free_mem(&file);
++
++      return retval;
++}
++
++
++errcode_t ext2fs_file_read(ext2_file_t file, void *buf,
++                         unsigned int wanted, unsigned int *got)
++{
++      ext2_filsys     fs;
++      errcode_t       retval = 0;
++      unsigned int    start, c, count = 0;
++      __u64           left;
++      char            *ptr = (char *) buf;
++
++      EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
++      fs = file->fs;
++
++      while ((file->pos < EXT2_I_SIZE(&file->inode)) && (wanted > 0)) {
++              retval = sync_buffer_position(file);
++              if (retval)
++                      goto fail;
++              retval = load_buffer(file, 0);
++              if (retval)
++                      goto fail;
++
++              start = file->pos % fs->blocksize;
++              c = fs->blocksize - start;
++              if (c > wanted)
++                      c = wanted;
++              left = EXT2_I_SIZE(&file->inode) - file->pos ;
++              if (c > left)
++                      c = left;
++      
++              memcpy(ptr, file->buf+start, c);
++              file->pos += c;
++              ptr += c;
++              count += c;
++              wanted -= c;
++      }
++      
++fail:
++      if (got)
++              *got = count;
++      return retval;
++}
++
++
++errcode_t ext2fs_file_write(ext2_file_t file, const void *buf,
++                          unsigned int nbytes, unsigned int *written)
++{
++      ext2_filsys     fs;
++      errcode_t       retval = 0;
++      unsigned int    start, c, count = 0;
++      const char      *ptr = (const char *) buf;
++
++      EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
++      fs = file->fs;
++
++      if (!(file->flags & EXT2_FILE_WRITE))
++              return EXT2_ET_FILE_RO;
++
++      while (nbytes > 0) {
++              retval = sync_buffer_position(file);
++              if (retval)
++                      goto fail;
++              
++              start = file->pos % fs->blocksize;
++              c = fs->blocksize - start;
++              if (c > nbytes)
++                      c = nbytes;
++
++              /*
++               * We only need to do a read-modify-update cycle if
++               * we're doing a partial write.
++               */
++              retval = load_buffer(file, (c == fs->blocksize));
++              if (retval)
++                      goto fail;
++
++              file->flags |= EXT2_FILE_BUF_DIRTY;
++              memcpy(file->buf+start, ptr, c);
++              file->pos += c;
++              ptr += c;
++              count += c;
++              nbytes -= c;
++      }
++      
++fail:
++      if (written)
++              *written = count;
++      return retval;
++}
++
++errcode_t ext2fs_file_llseek(ext2_file_t file, __u64 offset,
++                          int whence, __u64 *ret_pos)
++{
++      EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
++
++      if (whence == EXT2_SEEK_SET)
++              file->pos = offset;
++      else if (whence == EXT2_SEEK_CUR)
++              file->pos += offset;
++      else if (whence == EXT2_SEEK_END)
++              file->pos = EXT2_I_SIZE(&file->inode) + offset;
++      else
++              return EXT2_ET_INVALID_ARGUMENT;
++
++      if (ret_pos)
++              *ret_pos = file->pos;
++
++      return 0;
++}
++
++errcode_t ext2fs_file_lseek(ext2_file_t file, ext2_off_t offset,
++                          int whence, ext2_off_t *ret_pos)
++{
++      __u64           loffset, ret_loffset;
++      errcode_t       retval;
++      
++      loffset = offset;
++      retval = ext2fs_file_llseek(file, loffset, whence, &ret_loffset);
++      if (ret_pos)
++              *ret_pos = (ext2_off_t) ret_loffset;
++      return retval;
++}
++
++
++/*
++ * This function returns the size of the file, according to the inode
++ */
++errcode_t ext2fs_file_get_lsize(ext2_file_t file, __u64 *ret_size)
++{
++      if (file->magic != EXT2_ET_MAGIC_EXT2_FILE)
++              return EXT2_ET_MAGIC_EXT2_FILE;
++      *ret_size = EXT2_I_SIZE(&file->inode);
++      return 0;
++}
++
++/*
++ * This function returns the size of the file, according to the inode
++ */
++ext2_off_t ext2fs_file_get_size(ext2_file_t file)
++{
++      __u64   size;
++
++      if (ext2fs_file_get_lsize(file, &size))
++              return 0;
++      if ((size >> 32) != 0)
++              return 0;
++      return size;
++}
++
++/*
++ * This function sets the size of the file, truncating it if necessary
++ * 
++ * XXX still need to call truncate
++ */
++errcode_t ext2fs_file_set_size(ext2_file_t file, ext2_off_t size)
++{
++      errcode_t       retval;
++      EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
++      
++      file->inode.i_size = size;
++      file->inode.i_size_high = 0;
++      if (file->ino) {
++              retval = ext2fs_write_inode(file->fs, file->ino, &file->inode);
++              if (retval)
++                      return retval;
++      }
++
++      /* 
++       * XXX truncate inode if necessary
++       */
++
++      return 0;
++}
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/finddev.c busybox/e2fsprogs/ext2fs/finddev.c
+--- busybox-1.00/e2fsprogs/ext2fs/finddev.c    1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/finddev.c 2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,208 @@
++/*
++ * finddev.c -- this routine attempts to find a particular device in
++ *    /dev
++ * 
++ * Copyright (C) 2000 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <stdlib.h>
++#include <string.h>
++#if HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++#if HAVE_SYS_STAT_H
++#include <sys/stat.h>
++#endif
++#include <dirent.h>
++#if HAVE_ERRNO_H
++#include <errno.h>
++#endif
++#if HAVE_SYS_MKDEV_H
++#include <sys/mkdev.h>
++#endif
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++struct dir_list {
++      char    *name;
++      struct dir_list *next;
++};
++
++/*
++ * This function adds an entry to the directory list
++ */
++static void add_to_dirlist(const char *name, struct dir_list **list)
++{
++      struct dir_list *dp;
++
++      dp = malloc(sizeof(struct dir_list));
++      if (!dp)
++              return;
++      dp->name = malloc(strlen(name)+1);
++      if (!dp->name) {
++              free(dp);
++              return;
++      }
++      strcpy(dp->name, name);
++      dp->next = *list;
++      *list = dp;
++}
++
++/*
++ * This function frees a directory list
++ */
++static void free_dirlist(struct dir_list **list)
++{
++      struct dir_list *dp, *next;
++
++      for (dp = *list; dp; dp = next) {
++              next = dp->next;
++              free(dp->name);
++              free(dp);
++      }
++      *list = 0;
++}
++
++static int scan_dir(char *dir_name, dev_t device, struct dir_list **list,
++                  char **ret_path)
++{
++      DIR     *dir;
++      struct dirent *dp;
++      char    path[1024], *cp;
++      int     dirlen;
++      struct stat st;
++
++      dirlen = strlen(dir_name);
++      if ((dir = opendir(dir_name)) == NULL)
++              return errno;
++      dp = readdir(dir);
++      while (dp) {
++              if (dirlen + strlen(dp->d_name) + 2 >= sizeof(path))
++                      goto skip_to_next;
++              if (dp->d_name[0] == '.' &&
++                  ((dp->d_name[1] == 0) ||
++                   ((dp->d_name[1] == '.') && (dp->d_name[2] == 0))))
++                      goto skip_to_next;
++              sprintf(path, "%s/%s", dir_name, dp->d_name);
++              if (stat(path, &st) < 0)
++                      goto skip_to_next;
++              if (S_ISDIR(st.st_mode))
++                      add_to_dirlist(path, list);
++              if (S_ISBLK(st.st_mode) && st.st_rdev == device) {
++                      cp = malloc(strlen(path)+1);
++                      if (!cp) {
++                              closedir(dir);
++                              return ENOMEM;
++                      }
++                      strcpy(cp, path);
++                      *ret_path = cp;
++                      goto success;
++              }
++      skip_to_next:
++              dp = readdir(dir);
++      }
++success:
++      closedir(dir);
++      return 0;
++}
++
++/*
++ * This function finds the pathname to a block device with a given
++ * device number.  It returns a pointer to allocated memory to the
++ * pathname on success, and NULL on failure.
++ */
++char *ext2fs_find_block_device(dev_t device)
++{
++      struct dir_list *list = 0, *new_list = 0;
++      struct dir_list *current;
++      char    *ret_path = 0;
++
++      /*
++       * Add the starting directories to search...
++       */
++      add_to_dirlist("/devices", &list);
++      add_to_dirlist("/devfs", &list);
++      add_to_dirlist("/dev", &list);
++      
++      while (list) {
++              current = list;
++              list = list->next;
++#ifdef DEBUG
++              printf("Scanning directory %s\n", current->name);
++#endif
++              scan_dir(current->name, device, &new_list, &ret_path);
++              free(current->name);
++              free(current);
++              if (ret_path)
++                      break;
++              /*
++               * If we're done checking at this level, descend to
++               * the next level of subdirectories. (breadth-first)
++               */
++              if (list == 0) {
++                      list = new_list;
++                      new_list = 0;
++              }
++      }
++      free_dirlist(&list);
++      free_dirlist(&new_list);
++      return ret_path;
++}
++
++      
++#ifdef DEBUG
++int main(int argc, char** argv)
++{
++      char    *devname, *tmp;
++      int     major, minor;
++      dev_t   device;
++      const char *errmsg = "Couldn't parse %s: %s\n";
++
++      if ((argc != 2) && (argc != 3)) {
++              fprintf(stderr, "Usage: %s device_number\n", argv[0]);
++              fprintf(stderr, "\t: %s major minor\n", argv[0]);
++              exit(1);
++      }
++      if (argc == 2) {
++              device = strtoul(argv[1], &tmp, 0);
++              if (*tmp) {
++                      fprintf(stderr, errmsg, "device number", argv[1]);
++                      exit(1);
++              }
++      } else {
++              major = strtoul(argv[1], &tmp, 0);
++              if (*tmp) {
++                      fprintf(stderr, errmsg, "major number", argv[1]);
++                      exit(1);
++              }
++              minor = strtoul(argv[2], &tmp, 0);
++              if (*tmp) {
++                      fprintf(stderr, errmsg, "minor number", argv[2]);
++                      exit(1);
++              }
++              device = makedev(major, minor);
++              printf("Looking for device 0x%04x (%d:%d)\n", device,
++                     major, minor);
++      }
++      devname = ext2fs_find_block_device(device);
++      if (devname) {
++              printf("Found device!  %s\n", devname);
++              free(devname);
++      } else {
++              printf("Couldn't find device.\n");
++      }
++      return 0;
++}
++      
++#endif
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/flushb.c busybox/e2fsprogs/ext2fs/flushb.c
+--- busybox-1.00/e2fsprogs/ext2fs/flushb.c     1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/flushb.c  2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,82 @@
++/*
++ * flushb.c --- Hides system-dependent information for both syncing a
++ *    device to disk and to flush any buffers from disk cache.
++ * 
++ * Copyright (C) 2000 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#if HAVE_ERRNO_H
++#include <errno.h>
++#endif
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#if HAVE_SYS_IOCTL_H
++#include <sys/ioctl.h>
++#endif
++#if HAVE_SYS_MOUNT_H
++#include <sys/param.h>
++#include <sys/mount.h>                /* This may define BLKFLSBUF */
++#endif
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++/*
++ * For Linux, define BLKFLSBUF and FDFLUSH if necessary, since 
++ * not all portable header file does so for us.  This really should be
++ * fixed in the glibc header files.  (Recent glibcs appear to define
++ * BLKFLSBUF in sys/mount.h, but FDFLUSH still doesn't seem to be
++ * defined anywhere portable.)  Until then....
++ */
++#ifdef __linux__
++#ifndef BLKFLSBUF
++#define BLKFLSBUF     _IO(0x12,97)    /* flush buffer cache */
++#endif
++#ifndef FDFLUSH
++#define FDFLUSH               _IO(2,0x4b)     /* flush floppy disk */
++#endif
++#endif
++
++/*
++ * This function will sync a device/file, and optionally attempt to
++ * flush the buffer cache.  The latter is basically only useful for
++ * system benchmarks and for torturing systems in burn-in tests.  :)
++ */
++errcode_t ext2fs_sync_device(int fd, int flushb)
++{
++      /*
++       * We always sync the device in case we're running on old
++       * kernels for which we can lose data if we don't.  (There
++       * still is a race condition for those kernels, but this
++       * reduces it greatly.)
++       */
++      if (fsync (fd) == -1)
++              return errno;
++
++      if (flushb) {
++
++#ifdef BLKFLSBUF
++              if (ioctl (fd, BLKFLSBUF, 0) == 0)
++                      return 0;
++#else
++#ifdef __GNUC__
++ #warning BLKFLSBUF not defined
++#endif /* __GNUC__ */
++#endif
++#ifdef FDFLUSH
++              ioctl (fd, FDFLUSH, 0);   /* In case this is a floppy */
++#else
++#ifdef __GNUC__
++ #warning FDFLUSH not defined
++#endif /* __GNUC__ */
++#endif
++      }
++      return 0;
++}
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/freefs.c busybox/e2fsprogs/ext2fs/freefs.c
+--- busybox-1.00/e2fsprogs/ext2fs/freefs.c     1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/freefs.c  2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,147 @@
++/*
++ * freefs.c --- free an ext2 filesystem
++ * 
++ * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++
++#include "ext2_fs.h"
++#include "ext2fsP.h"
++
++static void ext2fs_free_inode_cache(struct ext2_inode_cache *icache);
++
++void ext2fs_free(ext2_filsys fs)
++{
++      if (!fs || (fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS))
++              return;
++      if (fs->image_io != fs->io) {
++              if (fs->image_io)
++                      io_channel_close(fs->image_io);
++      }
++      if (fs->io) {
++              io_channel_close(fs->io);
++      }
++      if (fs->device_name)
++              ext2fs_free_mem(&fs->device_name);
++      if (fs->super)
++              ext2fs_free_mem(&fs->super);
++      if (fs->orig_super)
++              ext2fs_free_mem(&fs->orig_super);
++      if (fs->group_desc)
++              ext2fs_free_mem(&fs->group_desc);
++      if (fs->block_map)
++              ext2fs_free_block_bitmap(fs->block_map);
++      if (fs->inode_map)
++              ext2fs_free_inode_bitmap(fs->inode_map);
++
++      if (fs->badblocks)
++              ext2fs_badblocks_list_free(fs->badblocks);
++      fs->badblocks = 0;
++
++      if (fs->dblist)
++              ext2fs_free_dblist(fs->dblist);
++
++      if (fs->icache)
++              ext2fs_free_inode_cache(fs->icache);
++      
++      fs->magic = 0;
++
++      ext2fs_free_mem(&fs);
++}
++
++void ext2fs_free_generic_bitmap(ext2fs_inode_bitmap bitmap)
++{
++      if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_GENERIC_BITMAP))
++              return;
++
++      bitmap->magic = 0;
++      if (bitmap->description) {
++              ext2fs_free_mem(&bitmap->description);
++              bitmap->description = 0;
++      }
++      if (bitmap->bitmap) {
++              ext2fs_free_mem(&bitmap->bitmap);
++              bitmap->bitmap = 0;
++      }
++      ext2fs_free_mem(&bitmap);
++}
++
++void ext2fs_free_inode_bitmap(ext2fs_inode_bitmap bitmap)
++{
++      if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_INODE_BITMAP))
++              return;
++
++      bitmap->magic = EXT2_ET_MAGIC_GENERIC_BITMAP;
++      ext2fs_free_generic_bitmap(bitmap);
++}
++
++void ext2fs_free_block_bitmap(ext2fs_block_bitmap bitmap)
++{
++      if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_BLOCK_BITMAP))
++              return;
++
++      bitmap->magic = EXT2_ET_MAGIC_GENERIC_BITMAP;
++      ext2fs_free_generic_bitmap(bitmap);
++}
++
++/*
++ * Free the inode cache structure
++ */
++static void ext2fs_free_inode_cache(struct ext2_inode_cache *icache)
++{
++      if (--icache->refcount)
++              return;
++      if (icache->buffer)
++              ext2fs_free_mem(&icache->buffer);
++      if (icache->cache)
++              ext2fs_free_mem(&icache->cache);
++      icache->buffer_blk = 0;
++      ext2fs_free_mem(&icache);
++}
++
++/*
++ * This procedure frees a badblocks list.
++ */
++void ext2fs_u32_list_free(ext2_u32_list bb)
++{
++      if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST)
++              return;
++
++      if (bb->list)
++              ext2fs_free_mem(&bb->list);
++      bb->list = 0;
++      ext2fs_free_mem(&bb);
++}
++
++void ext2fs_badblocks_list_free(ext2_badblocks_list bb)
++{
++      ext2fs_u32_list_free((ext2_u32_list) bb);
++}
++
++
++/*
++ * Free a directory block list
++ */
++void ext2fs_free_dblist(ext2_dblist dblist)
++{
++      if (!dblist || (dblist->magic != EXT2_ET_MAGIC_DBLIST))
++              return;
++
++      if (dblist->list)
++              ext2fs_free_mem(&dblist->list);
++      dblist->list = 0;
++      if (dblist->fs && dblist->fs->dblist == dblist)
++              dblist->fs->dblist = 0;
++      dblist->magic = 0;
++      ext2fs_free_mem(&dblist);
++}
++
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/gen_bitmap.c busybox/e2fsprogs/ext2fs/gen_bitmap.c
+--- busybox-1.00/e2fsprogs/ext2fs/gen_bitmap.c 1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/gen_bitmap.c      2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,48 @@
++/*
++ * gen_bitmap.c --- Generic bitmap routines that used to be inlined.
++ * 
++ * Copyright (C) 2001 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <fcntl.h>
++#include <time.h>
++#if HAVE_SYS_STAT_H
++#include <sys/stat.h>
++#endif
++#if HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++int ext2fs_mark_generic_bitmap(ext2fs_generic_bitmap bitmap,
++                                       __u32 bitno)
++{
++      if ((bitno < bitmap->start) || (bitno > bitmap->end)) {
++              ext2fs_warn_bitmap2(bitmap, EXT2FS_MARK_ERROR, bitno);
++              return 0;
++      }
++      return ext2fs_set_bit(bitno - bitmap->start, bitmap->bitmap);
++}
++
++int ext2fs_unmark_generic_bitmap(ext2fs_generic_bitmap bitmap,
++                                         blk_t bitno)
++{
++      if ((bitno < bitmap->start) || (bitno > bitmap->end)) {
++              ext2fs_warn_bitmap2(bitmap, EXT2FS_UNMARK_ERROR, bitno);
++              return 0;
++      }
++      return ext2fs_clear_bit(bitno - bitmap->start, bitmap->bitmap);
++}
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/get_pathname.c busybox/e2fsprogs/ext2fs/get_pathname.c
+--- busybox-1.00/e2fsprogs/ext2fs/get_pathname.c       1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/get_pathname.c    2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,157 @@
++/*
++ * get_pathname.c --- do directry/inode -> name translation
++ * 
++ * Copyright (C) 1993, 1994, 1995 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ *
++ *    ext2fs_get_pathname(fs, dir, ino, name)
++ *
++ *    This function translates takes two inode numbers into a
++ *    string, placing the result in <name>.  <dir> is the containing
++ *    directory inode, and <ino> is the inode number itself.  If
++ *    <ino> is zero, then ext2fs_get_pathname will return pathname
++ *    of the the directory <dir>.
++ * 
++ */
++
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++struct get_pathname_struct {
++      ext2_ino_t      search_ino;
++      ext2_ino_t      parent;
++      char            *name;
++      errcode_t       errcode;
++};
++
++#ifdef __TURBOC__
++ #pragma argsused
++#endif
++static int get_pathname_proc(struct ext2_dir_entry *dirent,
++                           int        offset EXT2FS_ATTR((unused)),
++                           int        blocksize EXT2FS_ATTR((unused)),
++                           char       *buf EXT2FS_ATTR((unused)),
++                           void       *priv_data)
++{
++      struct get_pathname_struct      *gp;
++      errcode_t                       retval;
++
++      gp = (struct get_pathname_struct *) priv_data;
++
++      if (((dirent->name_len & 0xFF) == 2) &&
++          !strncmp(dirent->name, "..", 2))
++              gp->parent = dirent->inode;
++      if (dirent->inode == gp->search_ino) {
++              retval = ext2fs_get_mem((dirent->name_len & 0xFF) + 1,
++                                      &gp->name);
++              if (retval) {
++                      gp->errcode = retval;
++                      return DIRENT_ABORT;
++              }
++              strncpy(gp->name, dirent->name, (dirent->name_len & 0xFF));
++              gp->name[dirent->name_len & 0xFF] = '\0';
++              return DIRENT_ABORT;
++      }
++      return 0;
++}
++
++static errcode_t ext2fs_get_pathname_int(ext2_filsys fs, ext2_ino_t dir, 
++                                       ext2_ino_t ino, int maxdepth, 
++                                       char *buf, char **name)
++{
++      struct get_pathname_struct gp;
++      char    *parent_name, *ret;
++      errcode_t       retval;
++
++      if (dir == ino) {
++              retval = ext2fs_get_mem(2, name);
++              if (retval)
++                      return retval;
++              strcpy(*name, (dir == EXT2_ROOT_INO) ? "/" : ".");
++              return 0;
++      }
++
++      if (!dir || (maxdepth < 0)) {
++              retval = ext2fs_get_mem(4, name);
++              if (retval)
++                      return retval;
++              strcpy(*name, "...");
++              return 0;
++      }
++
++      gp.search_ino = ino;
++      gp.parent = 0;
++      gp.name = 0;
++      gp.errcode = 0;
++      
++      retval = ext2fs_dir_iterate(fs, dir, 0, buf, get_pathname_proc, &gp);
++      if (retval)
++              goto cleanup;
++      if (gp.errcode) {
++              retval = gp.errcode;
++              goto cleanup;
++      }
++
++      retval = ext2fs_get_pathname_int(fs, gp.parent, dir, maxdepth-1,
++                                       buf, &parent_name);
++      if (retval)
++              goto cleanup;
++      if (!ino) {
++              *name = parent_name;
++              return 0;
++      }
++      
++      if (gp.name) 
++              retval = ext2fs_get_mem(strlen(parent_name)+strlen(gp.name)+2,
++                                      &ret);
++      else
++              retval = ext2fs_get_mem(strlen(parent_name)+5, &ret);
++      if (retval)
++              goto cleanup;
++      
++      ret[0] = 0;
++      if (parent_name[1])
++              strcat(ret, parent_name);
++      strcat(ret, "/");
++      if (gp.name)
++              strcat(ret, gp.name);
++      else
++              strcat(ret, "???");
++      *name = ret;
++      ext2fs_free_mem(&parent_name);
++      retval = 0;
++      
++cleanup:
++      if (gp.name)
++              ext2fs_free_mem(&gp.name);
++      return retval;
++}
++
++errcode_t ext2fs_get_pathname(ext2_filsys fs, ext2_ino_t dir, ext2_ino_t ino,
++                            char **name)
++{
++      char    *buf;
++      errcode_t       retval;
++
++      EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
++
++      retval = ext2fs_get_mem(fs->blocksize, &buf);
++      if (retval)
++              return retval;
++      if (dir == ino)
++              ino = 0;
++      retval = ext2fs_get_pathname_int(fs, dir, ino, 32, buf, name);
++      ext2fs_free_mem(&buf);
++      return retval;
++      
++}
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/getsectsize.c busybox/e2fsprogs/ext2fs/getsectsize.c
+--- busybox-1.00/e2fsprogs/ext2fs/getsectsize.c        1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/getsectsize.c     2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,57 @@
++/*
++ * getsectsize.c --- get the sector size of a device.
++ * 
++ * Copyright (C) 1995, 1995 Theodore Ts'o.
++ * Copyright (C) 2003 VMware, Inc.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#if HAVE_ERRNO_H
++#include <errno.h>
++#endif
++#include <fcntl.h>
++#ifdef HAVE_LINUX_FD_H
++#include <sys/ioctl.h>
++#include <linux/fd.h>
++#endif
++
++#if defined(__linux__) && defined(_IO) && !defined(BLKGETSIZE)
++#define BLKSSZGET  _IO(0x12,104)/* get block device sector size */
++#endif
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++/*
++ * Returns the number of blocks in a partition
++ */
++errcode_t ext2fs_get_device_sectsize(const char *file, int *sectsize)
++{
++      int     fd;
++
++#ifdef CONFIG_LFS
++      fd = open64(file, O_RDONLY);
++#else
++      fd = open(file, O_RDONLY);
++#endif
++      if (fd < 0)
++              return errno;
++
++#ifdef BLKSSZGET
++      if (ioctl(fd, BLKSSZGET, sectsize) >= 0) {
++              close(fd);
++              return 0;
++      }
++#endif
++      *sectsize = 0;
++      close(fd);
++      return 0;
++}
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/getsize.c busybox/e2fsprogs/ext2fs/getsize.c
+--- busybox-1.00/e2fsprogs/ext2fs/getsize.c    1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/getsize.c 2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,290 @@
++/*
++ * getsize.c --- get the size of a partition.
++ * 
++ * Copyright (C) 1995, 1995 Theodore Ts'o.
++ * Copyright (C) 2003 VMware, Inc.
++ *
++ * Windows version of ext2fs_get_device_size by Chris Li, VMware.
++ * 
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#if HAVE_ERRNO_H
++#include <errno.h>
++#endif
++#include <fcntl.h>
++#ifdef HAVE_SYS_IOCTL_H
++#include <sys/ioctl.h>
++#endif
++#ifdef HAVE_LINUX_FD_H
++#include <linux/fd.h>
++#endif
++#ifdef HAVE_SYS_DISKLABEL_H
++#include <sys/disklabel.h>
++#endif
++#ifdef HAVE_SYS_DISK_H
++#ifdef HAVE_SYS_QUEUE_H
++#include <sys/queue.h> /* for LIST_HEAD */
++#endif
++#include <sys/disk.h>
++#endif
++#ifdef __linux__
++#include <sys/utsname.h>
++#endif
++
++#if defined(__linux__) && defined(_IO) && !defined(BLKGETSIZE)
++#define BLKGETSIZE _IO(0x12,96)       /* return device size */
++#endif
++
++#if defined(__linux__) && defined(_IOR) && !defined(BLKGETSIZE64)
++#define BLKGETSIZE64 _IOR(0x12,114,size_t)    /* return device size in bytes (u64 *arg) */
++#endif
++
++#ifdef APPLE_DARWIN
++#define BLKGETSIZE DKIOCGETBLOCKCOUNT32
++#endif /* APPLE_DARWIN */
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++#if defined(__CYGWIN__) || defined (WIN32)
++#include "windows.h"
++#include "winioctl.h"
++
++#if (_WIN32_WINNT >= 0x0500)
++#define HAVE_GET_FILE_SIZE_EX 1
++#endif
++
++errcode_t ext2fs_get_device_size(const char *file, int blocksize,
++                               blk_t *retblocks)
++{
++      HANDLE dev;
++      PARTITION_INFORMATION pi;
++      DISK_GEOMETRY gi;
++      DWORD retbytes;
++#ifdef HAVE_GET_FILE_SIZE_EX
++      LARGE_INTEGER filesize;
++#else
++      DWORD filesize;
++#endif /* HAVE_GET_FILE_SIZE_EX */
++
++      dev = CreateFile(file, GENERIC_READ, 
++                       FILE_SHARE_READ | FILE_SHARE_WRITE ,
++                       NULL,  OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,  NULL); 
++ 
++      if (dev == INVALID_HANDLE_VALUE)
++              return EBADF;
++      if (DeviceIoControl(dev, IOCTL_DISK_GET_PARTITION_INFO,
++                          &pi, sizeof(PARTITION_INFORMATION),
++                          &pi, sizeof(PARTITION_INFORMATION),
++                          &retbytes, NULL)) {
++
++              *retblocks = pi.PartitionLength.QuadPart / blocksize;
++      
++      } else if (DeviceIoControl(dev, IOCTL_DISK_GET_DRIVE_GEOMETRY,
++                              &gi, sizeof(DISK_GEOMETRY),
++                              &gi, sizeof(DISK_GEOMETRY),
++                              &retbytes, NULL)) {
++
++              *retblocks = gi.BytesPerSector *
++                           gi.SectorsPerTrack *
++                           gi.TracksPerCylinder *
++                           gi.Cylinders.QuadPart / blocksize;
++
++#ifdef HAVE_GET_FILE_SIZE_EX
++      } else if (GetFileSizeEx(dev, &filesize)) {
++              *retblocks = filesize.QuadPart / blocksize;
++      }
++#else
++      } else {
++              filesize = GetFileSize(dev, NULL);
++              if (INVALID_FILE_SIZE != filesize) {
++                      *retblocks = filesize / blocksize;
++              }
++      }
++#endif /* HAVE_GET_FILE_SIZE_EX */
++
++      CloseHandle(dev);
++      return 0;
++}
++
++#else
++
++static int valid_offset (int fd, ext2_loff_t offset)
++{
++      char ch;
++
++      if (ext2fs_llseek (fd, offset, 0) < 0)
++              return 0;
++      if (read (fd, &ch, 1) < 1)
++              return 0;
++      return 1;
++}
++
++/*
++ * Returns the number of blocks in a partition
++ */
++errcode_t ext2fs_get_device_size(const char *file, int blocksize,
++                               blk_t *retblocks)
++{
++      int     fd;
++      int valid_blkgetsize64 = 1;
++#ifdef __linux__
++      struct          utsname ut;
++#endif
++      unsigned long long size64;
++      unsigned long   size;
++      ext2_loff_t high, low;
++#ifdef FDGETPRM
++      struct floppy_struct this_floppy;
++#endif
++#ifdef HAVE_SYS_DISKLABEL_H
++      int part;
++      struct disklabel lab;
++      struct partition *pp;
++      char ch;
++#endif /* HAVE_SYS_DISKLABEL_H */
++
++#ifdef CONFIG_LFS
++      fd = open64(file, O_RDONLY);
++#else
++      fd = open(file, O_RDONLY);
++#endif
++      if (fd < 0)
++              return errno;
++
++#ifdef DKIOCGETBLOCKCOUNT     /* For Apple Darwin */
++      if (ioctl(fd, DKIOCGETBLOCKCOUNT, &size64) >= 0) {
++              if ((sizeof(*retblocks) < sizeof(unsigned long long))
++                  && ((size64 / (blocksize / 512)) > 0xFFFFFFFF))
++                      return EFBIG;
++              close(fd);
++              *retblocks = size64 / (blocksize / 512);
++              return 0;
++      }
++#endif
++
++#ifdef BLKGETSIZE64
++#ifdef __linux__
++      if ((uname(&ut) == 0) &&
++          ((ut.release[0] == '2') && (ut.release[1] == '.') &&
++           (ut.release[2] < '6') && (ut.release[3] == '.')))
++              valid_blkgetsize64 = 0;
++#endif
++      if (valid_blkgetsize64 &&
++          ioctl(fd, BLKGETSIZE64, &size64) >= 0) {
++              if ((sizeof(*retblocks) < sizeof(unsigned long long))
++                  && ((size64 / blocksize) > 0xFFFFFFFF))
++                      return EFBIG;
++              close(fd);
++              *retblocks = size64 / blocksize;
++              return 0;
++      }
++#endif
++
++#ifdef BLKGETSIZE
++      if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
++              close(fd);
++              *retblocks = size / (blocksize / 512);
++              return 0;
++      }
++#endif
++
++#ifdef FDGETPRM
++      if (ioctl(fd, FDGETPRM, &this_floppy) >= 0) {
++              close(fd);
++              *retblocks = this_floppy.size / (blocksize / 512);
++              return 0;
++      }
++#endif
++
++#ifdef HAVE_SYS_DISKLABEL_H
++#if defined(DIOCGMEDIASIZE)
++      {
++          off_t ms;
++          u_int bs;
++          if (ioctl(fd, DIOCGMEDIASIZE, &ms) >= 0) {
++              *retblocks = ms / blocksize;
++              return 0;
++          }
++      }
++#elif defined(DIOCGDINFO)
++      /* old disklabel interface */
++      part = strlen(file) - 1;
++      if (part >= 0) {
++              ch = file[part];
++              if (isdigit(ch))
++                      part = 0;
++              else if (ch >= 'a' && ch <= 'h')
++                      part = ch - 'a';
++              else
++                      part = -1;
++      }
++      if (part >= 0 && (ioctl(fd, DIOCGDINFO, (char *)&lab) >= 0)) {
++              pp = &lab.d_partitions[part];
++              if (pp->p_size) {
++                      close(fd);
++                      *retblocks = pp->p_size / (blocksize / 512);
++                      return 0;
++              }
++      }
++#endif /* defined(DIOCG*) */
++#endif /* HAVE_SYS_DISKLABEL_H */
++
++      /*
++       * OK, we couldn't figure it out by using a specialized ioctl,
++       * which is generally the best way.  So do binary search to
++       * find the size of the partition.
++       */
++      low = 0;
++      for (high = 1024; valid_offset (fd, high); high *= 2)
++              low = high;
++      while (low < high - 1)
++      {
++              const ext2_loff_t mid = (low + high) / 2;
++
++              if (valid_offset (fd, mid))
++                      low = mid;
++              else
++                      high = mid;
++      }
++      valid_offset (fd, 0);
++      close(fd);
++      size64 = low + 1;
++      if ((sizeof(*retblocks) < sizeof(unsigned long long))
++          && ((size64 / blocksize) > 0xFFFFFFFF))
++              return EFBIG;
++      *retblocks = size64 / blocksize;
++      return 0;
++}
++
++#endif /* WIN32 */
++
++#ifdef DEBUG
++int main(int argc, char **argv)
++{
++      blk_t   blocks;
++      int     retval;
++      
++      if (argc < 2) {
++              fprintf(stderr, "Usage: %s device\n", argv[0]);
++              exit(1);
++      }
++
++      retval = ext2fs_get_device_size(argv[1], 1024, &blocks);
++      if (retval) {
++              com_err(argv[0], retval,
++                      "while calling ext2fs_get_device_size");
++              exit(1);
++      }
++      printf("Device %s has %d 1k blocks.\n", argv[1], blocks);
++      exit(0);
++}
++#endif
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/icount.c busybox/e2fsprogs/ext2fs/icount.c
+--- busybox-1.00/e2fsprogs/ext2fs/icount.c     1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/icount.c  2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,483 @@
++/*
++ * icount.c --- an efficient inode count abstraction
++ *
++ * Copyright (C) 1997 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <string.h>
++#include <stdio.h>
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++/*
++ * The data storage strategy used by icount relies on the observation
++ * that most inode counts are either zero (for non-allocated inodes),
++ * one (for most files), and only a few that are two or more
++ * (directories and files that are linked to more than one directory).
++ *
++ * Also, e2fsck tends to load the icount data sequentially.
++ *
++ * So, we use an inode bitmap to indicate which inodes have a count of
++ * one, and then use a sorted list to store the counts for inodes
++ * which are greater than one.
++ *
++ * We also use an optional bitmap to indicate which inodes are already
++ * in the sorted list, to speed up the use of this abstraction by
++ * e2fsck's pass 2.  Pass 2 increments inode counts as it finds them,
++ * so this extra bitmap avoids searching the sorted list to see if a
++ * particular inode is on the sorted list already.
++ */
++
++struct ext2_icount_el {
++      ext2_ino_t      ino;
++      __u16   count;
++};
++
++struct ext2_icount {
++      errcode_t               magic;
++      ext2fs_inode_bitmap     single;
++      ext2fs_inode_bitmap     multiple;
++      ext2_ino_t              count;
++      ext2_ino_t              size;
++      ext2_ino_t              num_inodes;
++      ext2_ino_t              cursor;
++      struct ext2_icount_el   *list;
++};
++
++void ext2fs_free_icount(ext2_icount_t icount)
++{
++      if (!icount)
++              return;
++
++      icount->magic = 0;
++      if (icount->list)
++              ext2fs_free_mem(&icount->list);
++      if (icount->single)
++              ext2fs_free_inode_bitmap(icount->single);
++      if (icount->multiple)
++              ext2fs_free_inode_bitmap(icount->multiple);
++      ext2fs_free_mem(&icount);
++}
++
++errcode_t ext2fs_create_icount2(ext2_filsys fs, int flags, unsigned int size,
++                              ext2_icount_t hint, ext2_icount_t *ret)
++{
++      ext2_icount_t   icount;
++      errcode_t       retval;
++      size_t          bytes;
++      ext2_ino_t      i;
++
++      if (hint) {
++              EXT2_CHECK_MAGIC(hint, EXT2_ET_MAGIC_ICOUNT);
++              if (hint->size > size)
++                      size = (size_t) hint->size;
++      }
++      
++      retval = ext2fs_get_mem(sizeof(struct ext2_icount), &icount);
++      if (retval)
++              return retval;
++      memset(icount, 0, sizeof(struct ext2_icount));
++
++      retval = ext2fs_allocate_inode_bitmap(fs, 0, 
++                                            &icount->single);
++      if (retval)
++              goto errout;
++
++      if (flags & EXT2_ICOUNT_OPT_INCREMENT) {
++              retval = ext2fs_allocate_inode_bitmap(fs, 0, 
++                                                    &icount->multiple);
++              if (retval)
++                      goto errout;
++      } else
++              icount->multiple = 0;
++
++      if (size) {
++              icount->size = size;
++      } else {
++              /*
++               * Figure out how many special case inode counts we will
++               * have.  We know we will need one for each directory;
++               * we also need to reserve some extra room for file links
++               */
++              retval = ext2fs_get_num_dirs(fs, &icount->size);
++              if (retval)
++                      goto errout;
++              icount->size += fs->super->s_inodes_count / 50;
++      }
++      
++      bytes = (size_t) (icount->size * sizeof(struct ext2_icount_el));
++#if 0
++      printf("Icount allocated %d entries, %d bytes.\n",
++             icount->size, bytes);
++#endif
++      retval = ext2fs_get_mem(bytes, &icount->list);
++      if (retval)
++              goto errout;
++      memset(icount->list, 0, bytes);
++
++      icount->magic = EXT2_ET_MAGIC_ICOUNT;
++      icount->count = 0;
++      icount->cursor = 0;
++      icount->num_inodes = fs->super->s_inodes_count;
++
++      /*
++       * Populate the sorted list with those entries which were
++       * found in the hint icount (since those are ones which will
++       * likely need to be in the sorted list this time around).
++       */
++      if (hint) {
++              for (i=0; i < hint->count; i++)
++                      icount->list[i].ino = hint->list[i].ino;
++              icount->count = hint->count;
++      }
++
++      *ret = icount;
++      return 0;
++
++errout:
++      ext2fs_free_icount(icount);
++      return(retval);
++}
++
++errcode_t ext2fs_create_icount(ext2_filsys fs, int flags, 
++                             unsigned int size,
++                             ext2_icount_t *ret)
++{
++      return ext2fs_create_icount2(fs, flags, size, 0, ret);
++}
++
++/*
++ * insert_icount_el() --- Insert a new entry into the sorted list at a
++ *    specified position.
++ */
++static struct ext2_icount_el *insert_icount_el(ext2_icount_t icount,
++                                          ext2_ino_t ino, int pos)
++{
++      struct ext2_icount_el   *el;
++      errcode_t               retval;
++      ext2_ino_t                      new_size = 0;
++      int                     num;
++
++      if (icount->count >= icount->size) {
++              if (icount->count) {
++                      new_size = icount->list[(unsigned)icount->count-1].ino;
++                      new_size = (ext2_ino_t) (icount->count * 
++                              ((float) icount->num_inodes / new_size));
++              }
++              if (new_size < (icount->size + 100))
++                      new_size = icount->size + 100;
++#if 0
++              printf("Reallocating icount %d entries...\n", new_size);
++#endif        
++              retval = ext2fs_resize_mem((size_t) icount->size *
++                                         sizeof(struct ext2_icount_el),
++                                         (size_t) new_size *
++                                         sizeof(struct ext2_icount_el),
++                                         &icount->list);
++              if (retval)
++                      return 0;
++              icount->size = new_size;
++      }
++      num = (int) icount->count - pos;
++      if (num < 0)
++              return 0;       /* should never happen */
++      if (num) {
++              memmove(&icount->list[pos+1], &icount->list[pos],
++                      sizeof(struct ext2_icount_el) * num);
++      }
++      icount->count++;
++      el = &icount->list[pos];
++      el->count = 0;
++      el->ino = ino;
++      return el;
++}
++
++/*
++ * get_icount_el() --- given an inode number, try to find icount
++ *    information in the sorted list.  If the create flag is set,
++ *    and we can't find an entry, create one in the sorted list.
++ */
++static struct ext2_icount_el *get_icount_el(ext2_icount_t icount,
++                                          ext2_ino_t ino, int create)
++{
++      float   range;
++      int     low, high, mid;
++      ext2_ino_t      lowval, highval;
++
++      if (!icount || !icount->list)
++              return 0;
++
++      if (create && ((icount->count == 0) ||
++                     (ino > icount->list[(unsigned)icount->count-1].ino))) {
++              return insert_icount_el(icount, ino, (unsigned) icount->count);
++      }
++      if (icount->count == 0)
++              return 0;
++      
++      if (icount->cursor >= icount->count)
++              icount->cursor = 0;
++      if (ino == icount->list[icount->cursor].ino)
++              return &icount->list[icount->cursor++];
++#if 0
++      printf("Non-cursor get_icount_el: %u\n", ino);
++#endif
++      low = 0;
++      high = (int) icount->count-1;
++      while (low <= high) {
++#if 0
++              mid = (low+high)/2;
++#else
++              if (low == high)
++                      mid = low;
++              else {
++                      /* Interpolate for efficiency */
++                      lowval = icount->list[low].ino;
++                      highval = icount->list[high].ino;
++
++                      if (ino < lowval)
++                              range = 0;
++                      else if (ino > highval)
++                              range = 1;
++                      else 
++                              range = ((float) (ino - lowval)) /
++                                      (highval - lowval);
++                      mid = low + ((int) (range * (high-low)));
++              }
++#endif
++              if (ino == icount->list[mid].ino) {
++                      icount->cursor = mid+1;
++                      return &icount->list[mid];
++              }
++              if (ino < icount->list[mid].ino)
++                      high = mid-1;
++              else
++                      low = mid+1;
++      }
++      /*
++       * If we need to create a new entry, it should be right at
++       * low (where high will be left at low-1).
++       */
++      if (create)
++              return insert_icount_el(icount, ino, low);
++      return 0;
++}
++
++errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *out)
++{
++      errcode_t       ret = 0;
++      unsigned int    i;
++      const char *bad = "bad icount";
++      
++      EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
++
++      if (icount->count > icount->size) {
++              fprintf(out, "%s: count > size\n", bad);
++              return EXT2_ET_INVALID_ARGUMENT;
++      }
++      for (i=1; i < icount->count; i++) {
++              if (icount->list[i-1].ino >= icount->list[i].ino) {
++                      fprintf(out, "%s: list[%d].ino=%u, list[%d].ino=%u\n",
++                              bad, i-1, icount->list[i-1].ino,
++                              i, icount->list[i].ino);
++                      ret = EXT2_ET_INVALID_ARGUMENT;
++              }
++      }
++      return ret;
++}
++
++errcode_t ext2fs_icount_fetch(ext2_icount_t icount, ext2_ino_t ino, __u16 *ret)
++{
++      struct ext2_icount_el   *el;
++      
++      EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
++
++      if (!ino || (ino > icount->num_inodes))
++              return EXT2_ET_INVALID_ARGUMENT;
++
++      if (ext2fs_test_inode_bitmap(icount->single, ino)) {
++              *ret = 1;
++              return 0;
++      }
++      if (icount->multiple &&
++          !ext2fs_test_inode_bitmap(icount->multiple, ino)) {
++              *ret = 0;
++              return 0;
++      }
++      el = get_icount_el(icount, ino, 0);
++      if (!el) {
++              *ret = 0;
++              return 0;
++      }
++      *ret = el->count;
++      return 0;
++}
++
++errcode_t ext2fs_icount_increment(ext2_icount_t icount, ext2_ino_t ino,
++                                __u16 *ret)
++{
++      struct ext2_icount_el   *el;
++
++      EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
++
++      if (!ino || (ino > icount->num_inodes))
++              return EXT2_ET_INVALID_ARGUMENT;
++
++      if (ext2fs_test_inode_bitmap(icount->single, ino)) {
++              /*
++               * If the existing count is 1, then we know there is
++               * no entry in the list.
++               */
++              el = get_icount_el(icount, ino, 1);
++              if (!el)
++                      return EXT2_ET_NO_MEMORY;
++              ext2fs_unmark_inode_bitmap(icount->single, ino);
++              el->count = 2;
++      } else if (icount->multiple) {
++              /*
++               * The count is either zero or greater than 1; if the
++               * inode is set in icount->multiple, then there should
++               * be an entry in the list, so find it using
++               * get_icount_el().
++               */
++              if (ext2fs_test_inode_bitmap(icount->multiple, ino)) {
++                      el = get_icount_el(icount, ino, 1);
++                      if (!el)
++                              return EXT2_ET_NO_MEMORY;
++                      el->count++;
++              } else {
++                      /*
++                       * The count was zero; mark the single bitmap
++                       * and return.
++                       */
++              zero_count:
++                      ext2fs_mark_inode_bitmap(icount->single, ino);
++                      if (ret)
++                              *ret = 1;
++                      return 0;
++              }
++      } else {
++              /*
++               * The count is either zero or greater than 1; try to
++               * find an entry in the list to determine which.
++               */
++              el = get_icount_el(icount, ino, 0);
++              if (!el) {
++                      /* No entry means the count was zero */
++                      goto zero_count;
++              }
++              el = get_icount_el(icount, ino, 1);
++              if (!el)
++                      return EXT2_ET_NO_MEMORY;
++              el->count++;
++      }
++      if (icount->multiple)
++              ext2fs_mark_inode_bitmap(icount->multiple, ino);
++      if (ret)
++              *ret = el->count;
++      return 0;
++}
++
++errcode_t ext2fs_icount_decrement(ext2_icount_t icount, ext2_ino_t ino,
++                                __u16 *ret)
++{
++      struct ext2_icount_el   *el;
++
++      if (!ino || (ino > icount->num_inodes))
++              return EXT2_ET_INVALID_ARGUMENT;
++
++      EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
++
++      if (ext2fs_test_inode_bitmap(icount->single, ino)) {
++              ext2fs_unmark_inode_bitmap(icount->single, ino);
++              if (icount->multiple)
++                      ext2fs_unmark_inode_bitmap(icount->multiple, ino);
++              else {
++                      el = get_icount_el(icount, ino, 0);
++                      if (el)
++                              el->count = 0;
++              }
++              if (ret)
++                      *ret = 0;
++              return 0;
++      }
++
++      if (icount->multiple &&
++          !ext2fs_test_inode_bitmap(icount->multiple, ino))
++              return EXT2_ET_INVALID_ARGUMENT;
++      
++      el = get_icount_el(icount, ino, 0);
++      if (!el || el->count == 0)
++              return EXT2_ET_INVALID_ARGUMENT;
++
++      el->count--;
++      if (el->count == 1)
++              ext2fs_mark_inode_bitmap(icount->single, ino);
++      if ((el->count == 0) && icount->multiple)
++              ext2fs_unmark_inode_bitmap(icount->multiple, ino);
++
++      if (ret)
++              *ret = el->count;
++      return 0;
++}
++
++errcode_t ext2fs_icount_store(ext2_icount_t icount, ext2_ino_t ino,
++                            __u16 count)
++{
++      struct ext2_icount_el   *el;
++
++      if (!ino || (ino > icount->num_inodes))
++              return EXT2_ET_INVALID_ARGUMENT;
++
++      EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
++
++      if (count == 1) {
++              ext2fs_mark_inode_bitmap(icount->single, ino);
++              if (icount->multiple)
++                      ext2fs_unmark_inode_bitmap(icount->multiple, ino);
++              return 0;
++      }
++      if (count == 0) {
++              ext2fs_unmark_inode_bitmap(icount->single, ino);
++              if (icount->multiple) {
++                      /*
++                       * If the icount->multiple bitmap is enabled,
++                       * we can just clear both bitmaps and we're done
++                       */
++                      ext2fs_unmark_inode_bitmap(icount->multiple, ino);
++              } else {
++                      el = get_icount_el(icount, ino, 0);
++                      if (el)
++                              el->count = 0;
++              }
++              return 0;
++      }
++
++      /*
++       * Get the icount element
++       */
++      el = get_icount_el(icount, ino, 1);
++      if (!el)
++              return EXT2_ET_NO_MEMORY;
++      el->count = count;
++      ext2fs_unmark_inode_bitmap(icount->single, ino);
++      if (icount->multiple)
++              ext2fs_mark_inode_bitmap(icount->multiple, ino);
++      return 0;
++}
++
++ext2_ino_t ext2fs_get_icount_size(ext2_icount_t icount)
++{
++      if (!icount || icount->magic != EXT2_ET_MAGIC_ICOUNT)
++              return 0;
++
++      return icount->size;
++}
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/imager.c busybox/e2fsprogs/ext2fs/imager.c
+--- busybox-1.00/e2fsprogs/ext2fs/imager.c     1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/imager.c  2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,387 @@
++/*
++ * image.c --- writes out the critical parts of the filesystem as a
++ *    flat file.
++ *
++ * Copyright (C) 2000 Theodore Ts'o.
++ *
++ * Note: this uses the POSIX IO interfaces, unlike most of the other
++ * functions in this library.  So sue me.  
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#if HAVE_ERRNO_H
++#include <errno.h>
++#endif
++#include <fcntl.h>
++#include <time.h>
++#if HAVE_SYS_STAT_H
++#include <sys/stat.h>
++#endif
++#if HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++#ifndef HAVE_TYPE_SSIZE_T
++typedef int ssize_t;
++#endif
++
++/*
++ * This function returns 1 if the specified block is all zeros
++ */
++static int check_zero_block(char *buf, int blocksize)
++{
++      char    *cp = buf;
++      int     left = blocksize;
++
++      while (left > 0) {
++              if (*cp++)
++                      return 0;
++              left--;
++      }
++      return 1;
++}
++
++/*
++ * Write the inode table out as a single block.
++ */
++#define BUF_BLOCKS    32
++
++errcode_t ext2fs_image_inode_write(ext2_filsys fs, int fd, int flags)
++{
++      unsigned int    group, left, c, d;
++      char            *buf, *cp;
++      blk_t           blk;
++      ssize_t         actual;
++      errcode_t       retval;
++
++      buf = malloc(fs->blocksize * BUF_BLOCKS);
++      if (!buf)
++              return ENOMEM;
++      
++      for (group = 0; group < fs->group_desc_count; group++) {
++              blk = fs->group_desc[(unsigned)group].bg_inode_table;
++              if (!blk)
++                      return EXT2_ET_MISSING_INODE_TABLE;
++              left = fs->inode_blocks_per_group;
++              while (left) {
++                      c = BUF_BLOCKS;
++                      if (c > left)
++                              c = left;
++                      retval = io_channel_read_blk(fs->io, blk, c, buf);
++                      if (retval)
++                              goto errout;
++                      cp = buf;
++                      while (c) {
++                              if (!(flags & IMAGER_FLAG_SPARSEWRITE)) {
++                                      d = c;
++                                      goto skip_sparse;
++                              }
++                              /* Skip zero blocks */
++                              if (check_zero_block(cp, fs->blocksize)) {
++                                      c--;
++                                      blk++;
++                                      left--;
++                                      cp += fs->blocksize;
++                                      lseek(fd, fs->blocksize, SEEK_CUR);
++                                      continue;
++                              }
++                              /* Find non-zero blocks */
++                              for (d=1; d < c; d++) {
++                                      if (check_zero_block(cp + d*fs->blocksize, fs->blocksize))
++                                              break;
++                              }
++                      skip_sparse:
++                              actual = write(fd, cp, fs->blocksize * d);
++                              if (actual == -1) {
++                                      retval = errno;
++                                      goto errout;
++                              }
++                              if (actual != (ssize_t) (fs->blocksize * d)) {
++                                      retval = EXT2_ET_SHORT_WRITE;
++                                      goto errout;
++                              }
++                              blk += d;
++                              left -= d;
++                              cp += fs->blocksize * d;
++                              c -= d;
++                      }
++              }
++      }
++      retval = 0;
++
++errout:
++      free(buf);
++      return retval;
++}
++
++/*
++ * Read in the inode table and stuff it into place
++ */
++errcode_t ext2fs_image_inode_read(ext2_filsys fs, int fd, 
++                                int flags EXT2FS_ATTR((unused)))
++{
++      unsigned int    group, c, left;
++      char            *buf;
++      blk_t           blk;
++      ssize_t         actual;
++      errcode_t       retval;
++
++      buf = malloc(fs->blocksize * BUF_BLOCKS);
++      if (!buf)
++              return ENOMEM;
++      
++      for (group = 0; group < fs->group_desc_count; group++) {
++              blk = fs->group_desc[(unsigned)group].bg_inode_table;
++              if (!blk) {
++                      retval = EXT2_ET_MISSING_INODE_TABLE;
++                      goto errout;
++              }
++              left = fs->inode_blocks_per_group;
++              while (left) {
++                      c = BUF_BLOCKS;
++                      if (c > left)
++                              c = left;
++                      actual = read(fd, buf, fs->blocksize * c);
++                      if (actual == -1) {
++                              retval = errno;
++                              goto errout;
++                      }
++                      if (actual != (ssize_t) (fs->blocksize * c)) {
++                              retval = EXT2_ET_SHORT_READ;
++                              goto errout;
++                      }
++                      retval = io_channel_write_blk(fs->io, blk, c, buf);
++                      if (retval)
++                              goto errout;
++                      
++                      blk += c;
++                      left -= c;
++              }
++      }
++      retval = ext2fs_flush_icache(fs);
++
++errout:
++      free(buf);
++      return retval;
++}
++
++/*
++ * Write out superblock and group descriptors
++ */
++errcode_t ext2fs_image_super_write(ext2_filsys fs, int fd, 
++                                 int flags EXT2FS_ATTR((unused)))
++{
++      char            *buf, *cp;
++      ssize_t         actual;
++      errcode_t       retval;
++
++      buf = malloc(fs->blocksize);
++      if (!buf)
++              return ENOMEM;
++
++      /*
++       * Write out the superblock
++       */
++      memset(buf, 0, fs->blocksize);
++      memcpy(buf, fs->super, SUPERBLOCK_SIZE);
++      actual = write(fd, buf, fs->blocksize);
++      if (actual == -1) {
++              retval = errno;
++              goto errout;
++      }
++      if (actual != (ssize_t) fs->blocksize) {
++              retval = EXT2_ET_SHORT_WRITE;
++              goto errout;
++      }
++
++      /*
++       * Now write out the block group descriptors
++       */
++      cp = (char *) fs->group_desc;
++      actual = write(fd, cp, fs->blocksize * fs->desc_blocks);
++      if (actual == -1) {
++              retval = errno;
++              goto errout;
++      }
++      if (actual != (ssize_t) (fs->blocksize * fs->desc_blocks)) {
++              retval = EXT2_ET_SHORT_WRITE;
++              goto errout;
++      }
++      
++      retval = 0;
++
++errout:
++      free(buf);
++      return retval;
++}
++
++/*
++ * Read the superblock and group descriptors and overwrite them.
++ */
++errcode_t ext2fs_image_super_read(ext2_filsys fs, int fd, 
++                                int flags EXT2FS_ATTR((unused)))
++{
++      char            *buf;
++      ssize_t         actual, size;
++      errcode_t       retval;
++
++      size = fs->blocksize * (fs->group_desc_count + 1);
++      buf = malloc(size);
++      if (!buf)
++              return ENOMEM;
++
++      /*
++       * Read it all in.
++       */
++      actual = read(fd, buf, size);
++      if (actual == -1) {
++              retval = errno;
++              goto errout;
++      }
++      if (actual != size) {
++              retval = EXT2_ET_SHORT_READ;
++              goto errout;
++      }
++
++      /*
++       * Now copy in the superblock and group descriptors
++       */
++      memcpy(fs->super, buf, SUPERBLOCK_SIZE);
++
++      memcpy(fs->group_desc, buf + fs->blocksize,
++             fs->blocksize * fs->group_desc_count);
++
++      retval = 0;
++
++errout:
++      free(buf);
++      return retval;
++}
++
++/*
++ * Write the block/inode bitmaps.
++ */
++errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags)
++{
++      char            *ptr;
++      int             c, size;
++      char            zero_buf[1024];
++      ssize_t         actual;
++      errcode_t       retval;
++
++      if (flags & IMAGER_FLAG_INODEMAP) {
++              if (!fs->inode_map) {
++                      retval = ext2fs_read_inode_bitmap(fs);
++                      if (retval)
++                              return retval;
++              }
++              ptr = fs->inode_map->bitmap;
++              size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
++      } else {
++              if (!fs->block_map) {
++                      retval = ext2fs_read_block_bitmap(fs);
++                      if (retval)
++                              return retval;
++              }
++              ptr = fs->block_map->bitmap;
++              size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
++      }
++      size = size * fs->group_desc_count;
++
++      actual = write(fd, ptr, size);
++      if (actual == -1) {
++              retval = errno;
++              goto errout;
++      }
++      if (actual != size) {
++              retval = EXT2_ET_SHORT_WRITE;
++              goto errout;
++      }
++      size = size % fs->blocksize;
++      memset(zero_buf, 0, sizeof(zero_buf));
++      if (size) {
++              size = fs->blocksize - size;
++              while (size) {
++                      c = size;
++                      if (c > (int) sizeof(zero_buf))
++                              c = sizeof(zero_buf);
++                      actual = write(fd, zero_buf, c);
++                      if (actual == -1) {
++                              retval = errno;
++                              goto errout;
++                      }
++                      if (actual != c) {
++                              retval = EXT2_ET_SHORT_WRITE;
++                              goto errout;
++                      }
++                      size -= c;
++              }
++      }
++      retval = 0;
++errout:
++      return (retval);
++}
++
++
++/*
++ * Read the block/inode bitmaps.
++ */
++errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags)
++{
++      char            *ptr, *buf = 0;
++      int             size;
++      ssize_t         actual;
++      errcode_t       retval;
++
++      if (flags & IMAGER_FLAG_INODEMAP) {
++              if (!fs->inode_map) {
++                      retval = ext2fs_read_inode_bitmap(fs);
++                      if (retval)
++                              return retval;
++              }
++              ptr = fs->inode_map->bitmap;
++              size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
++      } else {
++              if (!fs->block_map) {
++                      retval = ext2fs_read_block_bitmap(fs);
++                      if (retval)
++                              return retval;
++              }
++              ptr = fs->block_map->bitmap;
++              size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
++      }
++      size = size * fs->group_desc_count;
++
++      buf = malloc(size);
++      if (!buf)
++              return ENOMEM;
++
++      actual = read(fd, buf, size);
++      if (actual == -1) {
++              retval = errno;
++              goto errout;
++      }
++      if (actual != size) {
++              retval = EXT2_ET_SHORT_WRITE;
++              goto errout;
++      }
++      memcpy(ptr, buf, size);
++      
++      retval = 0;
++errout:
++      if (buf)
++              free(buf);
++      return (retval);
++}
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/ind_block.c busybox/e2fsprogs/ext2fs/ind_block.c
+--- busybox-1.00/e2fsprogs/ext2fs/ind_block.c  1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/ind_block.c       2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,66 @@
++/*
++ * ind_block.c --- indirect block I/O routines
++ * 
++ * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 
++ *    2001, 2002, 2003, 2004, 2005 by  Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++errcode_t ext2fs_read_ind_block(ext2_filsys fs, blk_t blk, void *buf)
++{
++      errcode_t       retval;
++      blk_t           *block_nr;
++      int             i;
++      int             limit = fs->blocksize >> 2;
++
++      if ((fs->flags & EXT2_FLAG_IMAGE_FILE) &&
++          (fs->io != fs->image_io))
++              memset(buf, 0, fs->blocksize);
++      else {
++              retval = io_channel_read_blk(fs->io, blk, 1, buf);
++              if (retval)
++                      return retval;
++      }
++#ifdef EXT2FS_ENABLE_SWAPFS
++      if (fs->flags & (EXT2_FLAG_SWAP_BYTES | EXT2_FLAG_SWAP_BYTES_READ)) {
++              block_nr = (blk_t *) buf;
++              for (i = 0; i < limit; i++, block_nr++)
++                      *block_nr = ext2fs_swab32(*block_nr);
++      }
++#endif
++      return 0;
++}
++
++errcode_t ext2fs_write_ind_block(ext2_filsys fs, blk_t blk, void *buf)
++{
++      blk_t           *block_nr;
++      int             i;
++      int             limit = fs->blocksize >> 2;
++
++      if (fs->flags & EXT2_FLAG_IMAGE_FILE)
++              return 0;
++
++#ifdef EXT2FS_ENABLE_SWAPFS
++      if (fs->flags & (EXT2_FLAG_SWAP_BYTES | EXT2_FLAG_SWAP_BYTES_WRITE)) {
++              block_nr = (blk_t *) buf;
++              for (i = 0; i < limit; i++, block_nr++)
++                      *block_nr = ext2fs_swab32(*block_nr);
++      }
++#endif
++      return io_channel_write_blk(fs->io, blk, 1, buf);
++}
++
++
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/initialize.c busybox/e2fsprogs/ext2fs/initialize.c
+--- busybox-1.00/e2fsprogs/ext2fs/initialize.c 1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/initialize.c      2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,387 @@
++/*
++ * initialize.c --- initialize a filesystem handle given superblock
++ *    parameters.  Used by mke2fs when initializing a filesystem.
++ * 
++ * Copyright (C) 1994, 1995, 1996 Theodore Ts'o.
++ * 
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <fcntl.h>
++#include <time.h>
++#if HAVE_SYS_STAT_H
++#include <sys/stat.h>
++#endif
++#if HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++#if defined(__linux__)    &&  defined(EXT2_OS_LINUX)
++#define CREATOR_OS EXT2_OS_LINUX
++#else
++#if defined(__GNU__)     &&   defined(EXT2_OS_HURD)
++#define CREATOR_OS EXT2_OS_HURD
++#else
++#if defined(__FreeBSD__) &&   defined(EXT2_OS_FREEBSD)
++#define CREATOR_OS EXT2_OS_FREEBSD
++#else
++#if defined(LITES)       &&   defined(EXT2_OS_LITES)
++#define CREATOR_OS EXT2_OS_LITES
++#else
++#define CREATOR_OS EXT2_OS_LINUX /* by default */
++#endif /* defined(LITES) && defined(EXT2_OS_LITES) */
++#endif /* defined(__FreeBSD__) && defined(EXT2_OS_FREEBSD) */
++#endif /* defined(__GNU__)     && defined(EXT2_OS_HURD) */
++#endif /* defined(__linux__)   && defined(EXT2_OS_LINUX) */
++      
++/*
++ * Note we override the kernel include file's idea of what the default
++ * check interval (never) should be.  It's a good idea to check at
++ * least *occasionally*, specially since servers will never rarely get
++ * to reboot, since Linux is so robust these days.  :-)
++ * 
++ * 180 days (six months) seems like a good value.
++ */
++#ifdef EXT2_DFL_CHECKINTERVAL
++#undef EXT2_DFL_CHECKINTERVAL
++#endif
++#define EXT2_DFL_CHECKINTERVAL (86400L * 180L)
++
++/*
++ * Calculate the number of GDT blocks to reserve for online filesystem growth.
++ * The absolute maximum number of GDT blocks we can reserve is determined by
++ * the number of block pointers that can fit into a single block.
++ */
++static int calc_reserved_gdt_blocks(ext2_filsys fs)
++{
++      struct ext2_super_block *sb = fs->super;
++      unsigned long bpg = sb->s_blocks_per_group;
++      unsigned int gdpb = fs->blocksize / sizeof(struct ext2_group_desc);
++      unsigned long max_blocks = 0xffffffff;
++      unsigned long rsv_groups;
++      int rsv_gdb;
++
++      /* We set it at 1024x the current filesystem size, or
++       * the upper block count limit (2^32), whichever is lower.
++       */
++      if (sb->s_blocks_count < max_blocks / 1024)
++              max_blocks = sb->s_blocks_count * 1024;
++      rsv_groups = (max_blocks - sb->s_first_data_block + bpg - 1) / bpg;
++      rsv_gdb = (rsv_groups + gdpb - 1) / gdpb - fs->desc_blocks;
++      if (rsv_gdb > EXT2_ADDR_PER_BLOCK(sb))
++              rsv_gdb = EXT2_ADDR_PER_BLOCK(sb);
++#ifdef RES_GDT_DEBUG
++      printf("max_blocks %lu, rsv_groups = %lu, rsv_gdb = %lu\n",
++             max_blocks, rsv_groups, rsv_gdb);
++#endif
++
++      return rsv_gdb;
++}
++
++errcode_t ext2fs_initialize(const char *name, int flags,
++                          struct ext2_super_block *param,
++                          io_manager manager, ext2_filsys *ret_fs)
++{
++      ext2_filsys     fs;
++      errcode_t       retval;
++      struct ext2_super_block *super;
++      int             frags_per_block;
++      unsigned int    rem;
++      unsigned int    overhead = 0;
++      blk_t           group_block;
++      unsigned int    ipg;
++      dgrp_t          i;
++      blk_t           numblocks;
++      int             rsv_gdt;
++      char            *buf;
++
++      if (!param || !param->s_blocks_count)
++              return EXT2_ET_INVALID_ARGUMENT;
++      
++      retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &fs);
++      if (retval)
++              return retval;
++      
++      memset(fs, 0, sizeof(struct struct_ext2_filsys));
++      fs->magic = EXT2_ET_MAGIC_EXT2FS_FILSYS;
++      fs->flags = flags | EXT2_FLAG_RW;
++      fs->umask = 022;
++#ifdef WORDS_BIGENDIAN
++      fs->flags |= EXT2_FLAG_SWAP_BYTES;
++#endif
++      retval = manager->open(name, IO_FLAG_RW, &fs->io);
++      if (retval)
++              goto cleanup;
++      fs->image_io = fs->io;
++      fs->io->app_data = fs;
++      retval = ext2fs_get_mem(strlen(name)+1, &fs->device_name);
++      if (retval)
++              goto cleanup;
++
++      strcpy(fs->device_name, name);
++      retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &super);
++      if (retval)
++              goto cleanup;
++      fs->super = super;
++
++      memset(super, 0, SUPERBLOCK_SIZE);
++
++#define set_field(field, default) (super->field = param->field ? \
++                                 param->field : (default))
++
++      super->s_magic = EXT2_SUPER_MAGIC;
++      super->s_state = EXT2_VALID_FS;
++
++      set_field(s_log_block_size, 0); /* default blocksize: 1024 bytes */
++      set_field(s_log_frag_size, 0); /* default fragsize: 1024 bytes */
++      set_field(s_first_data_block, super->s_log_block_size ? 0 : 1);
++      set_field(s_max_mnt_count, EXT2_DFL_MAX_MNT_COUNT);
++      set_field(s_errors, EXT2_ERRORS_DEFAULT);
++      set_field(s_feature_compat, 0);
++      set_field(s_feature_incompat, 0);
++      set_field(s_feature_ro_compat, 0);
++      set_field(s_first_meta_bg, 0);
++      if (super->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP) {
++              retval = EXT2_ET_UNSUPP_FEATURE;
++              goto cleanup;
++      }
++      if (super->s_feature_ro_compat & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP) {
++              retval = EXT2_ET_RO_UNSUPP_FEATURE;
++              goto cleanup;
++      }
++
++      set_field(s_rev_level, EXT2_GOOD_OLD_REV);
++      if (super->s_rev_level >= EXT2_DYNAMIC_REV) {
++              set_field(s_first_ino, EXT2_GOOD_OLD_FIRST_INO);
++              set_field(s_inode_size, EXT2_GOOD_OLD_INODE_SIZE);
++      }
++
++      set_field(s_checkinterval, EXT2_DFL_CHECKINTERVAL);
++      super->s_mkfs_time = super->s_lastcheck = time(NULL);
++
++      super->s_creator_os = CREATOR_OS;
++
++      fs->blocksize = EXT2_BLOCK_SIZE(super);
++      fs->fragsize = EXT2_FRAG_SIZE(super);
++      frags_per_block = fs->blocksize / fs->fragsize;
++
++      /* default: (fs->blocksize*8) blocks/group, up to 2^16 (GDT limit) */
++      set_field(s_blocks_per_group, fs->blocksize * 8);
++      if (super->s_blocks_per_group > EXT2_MAX_BLOCKS_PER_GROUP(super))
++              super->s_blocks_per_group = EXT2_MAX_BLOCKS_PER_GROUP(super);
++      super->s_frags_per_group = super->s_blocks_per_group * frags_per_block;
++      
++      super->s_blocks_count = param->s_blocks_count;
++      super->s_r_blocks_count = param->s_r_blocks_count;
++      if (super->s_r_blocks_count >= param->s_blocks_count) {
++              retval = EXT2_ET_INVALID_ARGUMENT;
++              goto cleanup;
++      }
++
++      /*
++       * If we're creating an external journal device, we don't need
++       * to bother with the rest.
++       */
++      if (super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
++              fs->group_desc_count = 0;
++              ext2fs_mark_super_dirty(fs);
++              *ret_fs = fs;
++              return 0;
++      }
++
++retry:
++      fs->group_desc_count = (super->s_blocks_count -
++                              super->s_first_data_block +
++                              EXT2_BLOCKS_PER_GROUP(super) - 1)
++              / EXT2_BLOCKS_PER_GROUP(super);
++      if (fs->group_desc_count == 0) {
++              retval = EXT2_ET_TOOSMALL;
++              goto cleanup;
++      }
++      fs->desc_blocks = (fs->group_desc_count +
++                         EXT2_DESC_PER_BLOCK(super) - 1)
++              / EXT2_DESC_PER_BLOCK(super);
++
++      i = fs->blocksize >= 4096 ? 1 : 4096 / fs->blocksize;
++      set_field(s_inodes_count, super->s_blocks_count / i);
++
++      /*
++       * Make sure we have at least EXT2_FIRST_INO + 1 inodes, so
++       * that we have enough inodes for the filesystem(!)
++       */
++      if (super->s_inodes_count < EXT2_FIRST_INODE(super)+1)
++              super->s_inodes_count = EXT2_FIRST_INODE(super)+1;
++      
++      /*
++       * There should be at least as many inodes as the user
++       * requested.  Figure out how many inodes per group that
++       * should be.  But make sure that we don't allocate more than
++       * one bitmap's worth of inodes each group.
++       */
++      ipg = (super->s_inodes_count + fs->group_desc_count - 1) /
++              fs->group_desc_count;
++      if (ipg > fs->blocksize * 8) {
++              if (super->s_blocks_per_group >= 256) {
++                      /* Try again with slightly different parameters */
++                      super->s_blocks_per_group -= 8;
++                      super->s_blocks_count = param->s_blocks_count;
++                      super->s_frags_per_group = super->s_blocks_per_group *
++                              frags_per_block;
++                      goto retry;
++              } else
++                      return EXT2_ET_TOO_MANY_INODES;
++      }
++
++      if (ipg > (unsigned) EXT2_MAX_INODES_PER_GROUP(super))
++              ipg = EXT2_MAX_INODES_PER_GROUP(super);
++
++      super->s_inodes_per_group = ipg;
++      if (super->s_inodes_count > ipg * fs->group_desc_count)
++              super->s_inodes_count = ipg * fs->group_desc_count;
++
++      /*
++       * Make sure the number of inodes per group completely fills
++       * the inode table blocks in the descriptor.  If not, add some
++       * additional inodes/group.  Waste not, want not...
++       */
++      fs->inode_blocks_per_group = (((super->s_inodes_per_group *
++                                      EXT2_INODE_SIZE(super)) +
++                                     EXT2_BLOCK_SIZE(super) - 1) /
++                                    EXT2_BLOCK_SIZE(super));
++      super->s_inodes_per_group = ((fs->inode_blocks_per_group *
++                                    EXT2_BLOCK_SIZE(super)) /
++                                   EXT2_INODE_SIZE(super));
++      /*
++       * Finally, make sure the number of inodes per group is a
++       * multiple of 8.  This is needed to simplify the bitmap
++       * splicing code.
++       */
++      super->s_inodes_per_group &= ~7;
++      fs->inode_blocks_per_group = (((super->s_inodes_per_group *
++                                      EXT2_INODE_SIZE(super)) +
++                                     EXT2_BLOCK_SIZE(super) - 1) /
++                                    EXT2_BLOCK_SIZE(super));
++
++      /*
++       * adjust inode count to reflect the adjusted inodes_per_group
++       */
++      super->s_inodes_count = super->s_inodes_per_group *
++              fs->group_desc_count;
++      super->s_free_inodes_count = super->s_inodes_count;
++
++      /*
++       * check the number of reserved group descriptor table blocks
++       */
++      if (super->s_feature_compat & EXT2_FEATURE_COMPAT_RESIZE_INODE)
++              rsv_gdt = calc_reserved_gdt_blocks(fs);
++      else
++              rsv_gdt = 0;
++      set_field(s_reserved_gdt_blocks, rsv_gdt);
++      if (super->s_reserved_gdt_blocks > EXT2_ADDR_PER_BLOCK(super)) {
++              retval = EXT2_ET_RES_GDT_BLOCKS;
++              goto cleanup;
++      }
++
++      /*
++       * Overhead is the number of bookkeeping blocks per group.  It
++       * includes the superblock backup, the group descriptor
++       * backups, the inode bitmap, the block bitmap, and the inode
++       * table.
++       */
++
++      overhead = (int) (2 + fs->inode_blocks_per_group);
++
++      if (ext2fs_bg_has_super(fs, fs->group_desc_count - 1))
++              overhead += 1 + fs->desc_blocks + super->s_reserved_gdt_blocks;
++
++      /* This can only happen if the user requested too many inodes */
++      if (overhead > super->s_blocks_per_group)
++              return EXT2_ET_TOO_MANY_INODES;
++
++      /*
++       * See if the last group is big enough to support the
++       * necessary data structures.  If not, we need to get rid of
++       * it.
++       */
++      rem = ((super->s_blocks_count - super->s_first_data_block) %
++             super->s_blocks_per_group);
++      if ((fs->group_desc_count == 1) && rem && (rem < overhead))
++              return EXT2_ET_TOOSMALL;
++      if (rem && (rem < overhead+50)) {
++              super->s_blocks_count -= rem;
++              goto retry;
++      }
++
++      /*
++       * At this point we know how big the filesystem will be.  So
++       * we can do any and all allocations that depend on the block
++       * count.
++       */
++
++      retval = ext2fs_get_mem(strlen(fs->device_name) + 80, &buf);
++      if (retval)
++              goto cleanup;
++      
++      sprintf(buf, "block bitmap for %s", fs->device_name);
++      retval = ext2fs_allocate_block_bitmap(fs, buf, &fs->block_map);
++      if (retval)
++              goto cleanup;
++      
++      sprintf(buf, "inode bitmap for %s", fs->device_name);
++      retval = ext2fs_allocate_inode_bitmap(fs, buf, &fs->inode_map);
++      if (retval)
++              goto cleanup;
++
++      ext2fs_free_mem(&buf);
++
++      retval = ext2fs_get_mem((size_t) fs->desc_blocks * fs->blocksize,
++                              &fs->group_desc);
++      if (retval)
++              goto cleanup;
++
++      memset(fs->group_desc, 0, (size_t) fs->desc_blocks * fs->blocksize);
++
++      /*
++       * Reserve the superblock and group descriptors for each
++       * group, and fill in the correct group statistics for group.
++       * Note that although the block bitmap, inode bitmap, and
++       * inode table have not been allocated (and in fact won't be
++       * by this routine), they are accounted for nevertheless.
++       */
++      group_block = super->s_first_data_block;
++      super->s_free_blocks_count = 0;
++      for (i = 0; i < fs->group_desc_count; i++) {
++              numblocks = ext2fs_reserve_super_and_bgd(fs, i, fs->block_map);
++
++              super->s_free_blocks_count += numblocks;
++              fs->group_desc[i].bg_free_blocks_count = numblocks;
++              fs->group_desc[i].bg_free_inodes_count =
++                      fs->super->s_inodes_per_group;
++              fs->group_desc[i].bg_used_dirs_count = 0;
++              
++              group_block += super->s_blocks_per_group;
++      }
++      
++      ext2fs_mark_super_dirty(fs);
++      ext2fs_mark_bb_dirty(fs);
++      ext2fs_mark_ib_dirty(fs);
++      
++      io_channel_set_blksize(fs->io, fs->blocksize);
++
++      *ret_fs = fs;
++      return 0;
++cleanup:
++      ext2fs_free(fs);
++      return retval;
++}
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/inline.c busybox/e2fsprogs/ext2fs/inline.c
+--- busybox-1.00/e2fsprogs/ext2fs/inline.c     1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/inline.c  2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,32 @@
++/*
++ * inline.c --- Includes the inlined functions defined in the header
++ *    files as standalone functions, in case the application program
++ *    is compiled with inlining turned off.
++ * 
++ * Copyright (C) 1993, 1994 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <fcntl.h>
++#include <time.h>
++#if HAVE_SYS_STAT_H
++#include <sys/stat.h>
++#endif
++#if HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++
++#include "ext2_fs.h"
++#define INCLUDE_INLINE_FUNCS
++#include "ext2fs.h"
++
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/inode.c busybox/e2fsprogs/ext2fs/inode.c
+--- busybox-1.00/e2fsprogs/ext2fs/inode.c      1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/inode.c   2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,794 @@
++/*
++ * inode.c --- utility routines to read and write inodes
++ * 
++ * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#if HAVE_ERRNO_H
++#include <errno.h>
++#endif
++#if HAVE_SYS_STAT_H
++#include <sys/stat.h>
++#endif
++#if HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++
++#include "ext2_fs.h"
++#include "ext2fsP.h"
++#include "e2image.h"
++
++struct ext2_struct_inode_scan {
++      errcode_t               magic;
++      ext2_filsys             fs;
++      ext2_ino_t              current_inode;
++      blk_t                   current_block;
++      dgrp_t                  current_group;
++      ext2_ino_t              inodes_left;
++      blk_t                   blocks_left;
++      dgrp_t                  groups_left;
++      blk_t                   inode_buffer_blocks;
++      char *                  inode_buffer;
++      int                     inode_size;
++      char *                  ptr;
++      int                     bytes_left;
++      char                    *temp_buffer;
++      errcode_t               (*done_group)(ext2_filsys fs,
++                                            ext2_inode_scan scan,
++                                            dgrp_t group,
++                                            void * priv_data);
++      void *                  done_group_data;
++      int                     bad_block_ptr;
++      int                     scan_flags;
++      int                     reserved[6];
++};
++
++/*
++ * This routine flushes the icache, if it exists.
++ */
++errcode_t ext2fs_flush_icache(ext2_filsys fs)
++{
++      int     i;
++      
++      if (!fs->icache)
++              return 0;
++
++      for (i=0; i < fs->icache->cache_size; i++)
++              fs->icache->cache[i].ino = 0;
++
++      fs->icache->buffer_blk = 0;
++      return 0;
++}
++
++static errcode_t create_icache(ext2_filsys fs)
++{
++      errcode_t       retval;
++      
++      if (fs->icache)
++              return 0;
++      retval = ext2fs_get_mem(sizeof(struct ext2_inode_cache), &fs->icache);
++      if (retval)
++              return retval;
++
++      memset(fs->icache, 0, sizeof(struct ext2_inode_cache));
++      retval = ext2fs_get_mem(fs->blocksize, &fs->icache->buffer);
++      if (retval) {
++              ext2fs_free_mem(&fs->icache);
++              return retval;
++      }
++      fs->icache->buffer_blk = 0;
++      fs->icache->cache_last = -1;
++      fs->icache->cache_size = 4;
++      fs->icache->refcount = 1;
++      retval = ext2fs_get_mem(sizeof(struct ext2_inode_cache_ent)
++                              * fs->icache->cache_size,
++                              &fs->icache->cache);
++      if (retval) {
++              ext2fs_free_mem(&fs->icache->buffer);
++              ext2fs_free_mem(&fs->icache);
++              return retval;
++      }
++      ext2fs_flush_icache(fs);
++      return 0;
++}
++
++errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks,
++                               ext2_inode_scan *ret_scan)
++{
++      ext2_inode_scan scan;
++      errcode_t       retval;
++      errcode_t (*save_get_blocks)(ext2_filsys f, ext2_ino_t ino, blk_t *blocks);
++
++      EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
++
++      /*
++       * If fs->badblocks isn't set, then set it --- since the inode
++       * scanning functions require it.
++       */
++      if (fs->badblocks == 0) {
++              /*
++               * Temporarly save fs->get_blocks and set it to zero,
++               * for compatibility with old e2fsck's.
++               */
++              save_get_blocks = fs->get_blocks;
++              fs->get_blocks = 0;
++              retval = ext2fs_read_bb_inode(fs, &fs->badblocks);
++              if (retval && fs->badblocks) {
++                      ext2fs_badblocks_list_free(fs->badblocks);
++                      fs->badblocks = 0;
++              }
++              fs->get_blocks = save_get_blocks;
++      }
++
++      retval = ext2fs_get_mem(sizeof(struct ext2_struct_inode_scan), &scan);
++      if (retval)
++              return retval;
++      memset(scan, 0, sizeof(struct ext2_struct_inode_scan));
++
++      scan->magic = EXT2_ET_MAGIC_INODE_SCAN;
++      scan->fs = fs;
++      scan->inode_size = EXT2_INODE_SIZE(fs->super);
++      scan->bytes_left = 0;
++      scan->current_group = 0;
++      scan->groups_left = fs->group_desc_count - 1;
++      scan->inode_buffer_blocks = buffer_blocks ? buffer_blocks : 8;
++      scan->current_block = scan->fs->
++              group_desc[scan->current_group].bg_inode_table;
++      scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super);
++      scan->blocks_left = scan->fs->inode_blocks_per_group;
++      retval = ext2fs_get_mem((size_t) (scan->inode_buffer_blocks * 
++                                        fs->blocksize),
++                              &scan->inode_buffer);
++      scan->done_group = 0;
++      scan->done_group_data = 0;
++      scan->bad_block_ptr = 0;
++      if (retval) {
++              ext2fs_free_mem(&scan);
++              return retval;
++      }
++      retval = ext2fs_get_mem(scan->inode_size, &scan->temp_buffer);
++      if (retval) {
++              ext2fs_free_mem(&scan->inode_buffer);
++              ext2fs_free_mem(&scan);
++              return retval;
++      }
++      if (scan->fs->badblocks && scan->fs->badblocks->num)
++              scan->scan_flags |= EXT2_SF_CHK_BADBLOCKS;
++      *ret_scan = scan;
++      return 0;
++}
++
++void ext2fs_close_inode_scan(ext2_inode_scan scan)
++{
++      if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN))
++              return;
++      
++      ext2fs_free_mem(&scan->inode_buffer);
++      scan->inode_buffer = NULL;
++      ext2fs_free_mem(&scan->temp_buffer);
++      scan->temp_buffer = NULL;
++      ext2fs_free_mem(&scan);
++      return;
++}
++
++void ext2fs_set_inode_callback(ext2_inode_scan scan,
++                             errcode_t (*done_group)(ext2_filsys fs,
++                                                     ext2_inode_scan scan,
++                                                     dgrp_t group,
++                                                     void * priv_data),
++                             void *done_group_data)
++{
++      if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN))
++              return;
++      
++      scan->done_group = done_group;
++      scan->done_group_data = done_group_data;
++}
++
++int ext2fs_inode_scan_flags(ext2_inode_scan scan, int set_flags,
++                          int clear_flags)
++{
++      int     old_flags;
++
++      if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN))
++              return 0;
++
++      old_flags = scan->scan_flags;
++      scan->scan_flags &= ~clear_flags;
++      scan->scan_flags |= set_flags;
++      return old_flags;
++}
++
++/*
++ * This function is called by ext2fs_get_next_inode when it needs to
++ * get ready to read in a new blockgroup.
++ */
++static errcode_t get_next_blockgroup(ext2_inode_scan scan)
++{
++      scan->current_group++;
++      scan->groups_left--;
++                      
++      scan->current_block = scan->fs->
++              group_desc[scan->current_group].bg_inode_table;
++
++      scan->current_inode = scan->current_group *
++              EXT2_INODES_PER_GROUP(scan->fs->super);
++
++      scan->bytes_left = 0;
++      scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super);
++      scan->blocks_left = scan->fs->inode_blocks_per_group;
++      return 0;
++}
++
++errcode_t ext2fs_inode_scan_goto_blockgroup(ext2_inode_scan scan,
++                                          int group)
++{
++      scan->current_group = group - 1;
++      scan->groups_left = scan->fs->group_desc_count - group;
++      return get_next_blockgroup(scan);
++}
++
++/*
++ * This function is called by get_next_blocks() to check for bad
++ * blocks in the inode table.
++ *
++ * This function assumes that badblocks_list->list is sorted in
++ * increasing order.
++ */
++static errcode_t check_for_inode_bad_blocks(ext2_inode_scan scan,
++                                          blk_t *num_blocks)
++{
++      blk_t   blk = scan->current_block;
++      badblocks_list  bb = scan->fs->badblocks;
++
++      /*
++       * If the inode table is missing, then obviously there are no
++       * bad blocks.  :-)
++       */
++      if (blk == 0)
++              return 0;
++
++      /*
++       * If the current block is greater than the bad block listed
++       * in the bad block list, then advance the pointer until this
++       * is no longer the case.  If we run out of bad blocks, then
++       * we don't need to do any more checking!
++       */
++      while (blk > bb->list[scan->bad_block_ptr]) {
++              if (++scan->bad_block_ptr >= bb->num) {
++                      scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS;
++                      return 0;
++              }
++      }
++
++      /*
++       * If the current block is equal to the bad block listed in
++       * the bad block list, then handle that one block specially.
++       * (We could try to handle runs of bad blocks, but that
++       * only increases CPU efficiency by a small amount, at the
++       * expense of a huge expense of code complexity, and for an
++       * uncommon case at that.)
++       */
++      if (blk == bb->list[scan->bad_block_ptr]) {
++              scan->scan_flags |= EXT2_SF_BAD_INODE_BLK;
++              *num_blocks = 1;
++              if (++scan->bad_block_ptr >= bb->num)
++                      scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS;
++              return 0;
++      }
++
++      /*
++       * If there is a bad block in the range that we're about to
++       * read in, adjust the number of blocks to read so that we we
++       * don't read in the bad block.  (Then the next block to read
++       * will be the bad block, which is handled in the above case.)
++       */
++      if ((blk + *num_blocks) > bb->list[scan->bad_block_ptr])
++              *num_blocks = (int) (bb->list[scan->bad_block_ptr] - blk);
++
++      return 0;
++}
++
++/*
++ * This function is called by ext2fs_get_next_inode when it needs to
++ * read in more blocks from the current blockgroup's inode table.
++ */
++static errcode_t get_next_blocks(ext2_inode_scan scan)
++{
++      blk_t           num_blocks;
++      errcode_t       retval;
++
++      /*
++       * Figure out how many blocks to read; we read at most
++       * inode_buffer_blocks, and perhaps less if there aren't that
++       * many blocks left to read.
++       */
++      num_blocks = scan->inode_buffer_blocks;
++      if (num_blocks > scan->blocks_left)
++              num_blocks = scan->blocks_left;
++
++      /*
++       * If the past block "read" was a bad block, then mark the
++       * left-over extra bytes as also being bad.
++       */
++      if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK) {
++              if (scan->bytes_left)
++                      scan->scan_flags |= EXT2_SF_BAD_EXTRA_BYTES;
++              scan->scan_flags &= ~EXT2_SF_BAD_INODE_BLK;
++      }
++
++      /*
++       * Do inode bad block processing, if necessary.
++       */
++      if (scan->scan_flags & EXT2_SF_CHK_BADBLOCKS) {
++              retval = check_for_inode_bad_blocks(scan, &num_blocks);
++              if (retval)
++                      return retval;
++      }
++              
++      if ((scan->scan_flags & EXT2_SF_BAD_INODE_BLK) ||
++          (scan->current_block == 0)) {
++              memset(scan->inode_buffer, 0,
++                     (size_t) num_blocks * scan->fs->blocksize);
++      } else {
++              retval = io_channel_read_blk(scan->fs->io,
++                                           scan->current_block,
++                                           (int) num_blocks,
++                                           scan->inode_buffer);
++              if (retval)
++                      return EXT2_ET_NEXT_INODE_READ;
++      }
++      scan->ptr = scan->inode_buffer;
++      scan->bytes_left = num_blocks * scan->fs->blocksize;
++
++      scan->blocks_left -= num_blocks;
++      if (scan->current_block)
++              scan->current_block += num_blocks;
++      return 0;
++}
++
++#if 0
++/*
++ * Returns 1 if the entire inode_buffer has a non-zero size and
++ * contains all zeros.  (Not just deleted inodes, since that means
++ * that part of the inode table was used at one point; we want all
++ * zeros, which means that the inode table is pristine.)
++ */
++static inline int is_empty_scan(ext2_inode_scan scan)
++{
++      int     i;
++      
++      if (scan->bytes_left == 0)
++              return 0;
++
++      for (i=0; i < scan->bytes_left; i++)
++              if (scan->ptr[i])
++                      return 0;
++      return 1;
++}
++#endif
++
++errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, ext2_ino_t *ino,
++                                   struct ext2_inode *inode, int bufsize)
++{
++      errcode_t       retval;
++      int             extra_bytes = 0;
++      
++      EXT2_CHECK_MAGIC(scan, EXT2_ET_MAGIC_INODE_SCAN);
++
++      /*
++       * Do we need to start reading a new block group?
++       */
++      if (scan->inodes_left <= 0) {
++      force_new_group:
++              if (scan->done_group) {
++                      retval = (scan->done_group)
++                              (scan->fs, scan, scan->current_group,
++                               scan->done_group_data);
++                      if (retval)
++                              return retval;
++              }
++              if (scan->groups_left <= 0) {
++                      *ino = 0;
++                      return 0;
++              }
++              retval = get_next_blockgroup(scan);
++              if (retval)
++                      return retval;
++      }
++      /*
++       * This is done outside the above if statement so that the
++       * check can be done for block group #0.
++       */
++      if (scan->current_block == 0) {
++              if (scan->scan_flags & EXT2_SF_SKIP_MISSING_ITABLE) {
++                      goto force_new_group;
++              } else
++                      return EXT2_ET_MISSING_INODE_TABLE;
++      }
++      
++
++      /*
++       * Have we run out of space in the inode buffer?  If so, we
++       * need to read in more blocks.
++       */
++      if (scan->bytes_left < scan->inode_size) {
++              memcpy(scan->temp_buffer, scan->ptr, scan->bytes_left);
++              extra_bytes = scan->bytes_left;
++
++              retval = get_next_blocks(scan);
++              if (retval)
++                      return retval;
++#if 0
++              /*
++               * XXX test  Need check for used inode somehow.
++               * (Note: this is hard.)
++               */
++              if (is_empty_scan(scan))
++                      goto force_new_group;
++#endif
++      }
++
++      retval = 0;
++      if (extra_bytes) {
++              memcpy(scan->temp_buffer+extra_bytes, scan->ptr,
++                     scan->inode_size - extra_bytes);
++              scan->ptr += scan->inode_size - extra_bytes;
++              scan->bytes_left -= scan->inode_size - extra_bytes;
++
++#ifdef EXT2FS_ENABLE_SWAPFS
++              if ((scan->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
++                  (scan->fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
++                      ext2fs_swap_inode_full(scan->fs, 
++                              (struct ext2_inode_large *) inode,
++                              (struct ext2_inode_large *) scan->temp_buffer, 
++                              0, bufsize);
++              else
++#endif
++                      *inode = *((struct ext2_inode *) scan->temp_buffer);
++              if (scan->scan_flags & EXT2_SF_BAD_EXTRA_BYTES)
++                      retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE;
++              scan->scan_flags &= ~EXT2_SF_BAD_EXTRA_BYTES;
++      } else {
++#ifdef EXT2FS_ENABLE_SWAPFS
++              if ((scan->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
++                  (scan->fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
++                      ext2fs_swap_inode_full(scan->fs, 
++                              (struct ext2_inode_large *) inode,
++                              (struct ext2_inode_large *) scan->ptr,
++                              0, bufsize);
++              else
++#endif
++                      memcpy(inode, scan->ptr, bufsize);
++              scan->ptr += scan->inode_size;
++              scan->bytes_left -= scan->inode_size;
++              if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK)
++                      retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE;
++      }
++
++      scan->inodes_left--;
++      scan->current_inode++;
++      *ino = scan->current_inode;
++      return retval;
++}
++
++errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ext2_ino_t *ino,
++                              struct ext2_inode *inode)
++{
++      return ext2fs_get_next_inode_full(scan, ino, inode,
++                                              sizeof(struct ext2_inode));
++}
++
++/*
++ * Functions to read and write a single inode.
++ */
++errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
++                               struct ext2_inode * inode, int bufsize)
++{
++      unsigned long   group, block, block_nr, offset;
++      char            *ptr;
++      errcode_t       retval;
++      int             clen, i, inodes_per_block, length;
++      io_channel      io;
++
++      EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
++
++      /* Check to see if user has an override function */
++      if (fs->read_inode) {
++              retval = (fs->read_inode)(fs, ino, inode);
++              if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
++                      return retval;
++      }
++      /* Create inode cache if not present */
++      if (!fs->icache) {
++              retval = create_icache(fs);
++              if (retval)
++                      return retval;
++      }
++      /* Check to see if it's in the inode cache */
++      if (bufsize == sizeof(struct ext2_inode)) {
++              /* only old good inode can be retrieve from the cache */
++              for (i=0; i < fs->icache->cache_size; i++) {
++                      if (fs->icache->cache[i].ino == ino) {
++                              *inode = fs->icache->cache[i].inode;
++                              return 0;
++                      }
++              }
++      }
++      if ((ino == 0) || (ino > fs->super->s_inodes_count))
++              return EXT2_ET_BAD_INODE_NUM;
++      if (fs->flags & EXT2_FLAG_IMAGE_FILE) {
++              inodes_per_block = fs->blocksize / EXT2_INODE_SIZE(fs->super);
++              block_nr = fs->image_header->offset_inode / fs->blocksize;
++              block_nr += (ino - 1) / inodes_per_block;
++              offset = ((ino - 1) % inodes_per_block) *
++                      EXT2_INODE_SIZE(fs->super);
++              io = fs->image_io;
++      } else {
++              group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
++              offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) *
++                      EXT2_INODE_SIZE(fs->super);
++              block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super);
++              if (!fs->group_desc[(unsigned)group].bg_inode_table)
++                      return EXT2_ET_MISSING_INODE_TABLE;
++              block_nr = fs->group_desc[(unsigned)group].bg_inode_table + 
++                      block;
++              io = fs->io;
++      }
++      offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
++
++      length = EXT2_INODE_SIZE(fs->super);
++      if (bufsize < length)
++              length = bufsize;
++
++      ptr = (char *) inode;
++      while (length) {
++              clen = length;
++              if ((offset + length) > fs->blocksize)
++                      clen = fs->blocksize - offset;
++
++              if (block_nr != fs->icache->buffer_blk) {
++                      retval = io_channel_read_blk(io, block_nr, 1,
++                                                   fs->icache->buffer);
++                      if (retval)
++                              return retval;
++                      fs->icache->buffer_blk = block_nr;
++              }
++
++              memcpy(ptr, ((char *) fs->icache->buffer) + (unsigned) offset,
++                     clen);
++
++              offset = 0;
++              length -= clen;
++              ptr += clen;
++              block_nr++;
++      }
++
++#ifdef EXT2FS_ENABLE_SWAPFS
++      if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
++          (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
++              ext2fs_swap_inode_full(fs, (struct ext2_inode_large *) inode, 
++                                     (struct ext2_inode_large *) inode, 
++                                     0, length);
++#endif
++
++      /* Update the inode cache */
++      fs->icache->cache_last = (fs->icache->cache_last + 1) %
++              fs->icache->cache_size;
++      fs->icache->cache[fs->icache->cache_last].ino = ino;
++      fs->icache->cache[fs->icache->cache_last].inode = *inode;
++      
++      return 0;
++}
++
++errcode_t ext2fs_read_inode(ext2_filsys fs, ext2_ino_t ino,
++                          struct ext2_inode * inode)
++{
++      return ext2fs_read_inode_full(fs, ino, inode,
++                                      sizeof(struct ext2_inode));
++}
++
++errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
++                                struct ext2_inode * inode, int bufsize)
++{
++      unsigned long group, block, block_nr, offset;
++      errcode_t retval = 0;
++      struct ext2_inode_large temp_inode, *w_inode;
++      char *ptr;
++      int clen, i, length;
++
++      EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
++
++      /* Check to see if user provided an override function */
++      if (fs->write_inode) {
++              retval = (fs->write_inode)(fs, ino, inode);
++              if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
++                      return retval;
++      }
++
++      /* Check to see if the inode cache needs to be updated */
++      if (fs->icache) {
++              for (i=0; i < fs->icache->cache_size; i++) {
++                      if (fs->icache->cache[i].ino == ino) {
++                              fs->icache->cache[i].inode = *inode;
++                              break;
++                      }
++              }
++      } else {
++              retval = create_icache(fs);
++              if (retval)
++                      return retval;
++      }
++              
++      if (!(fs->flags & EXT2_FLAG_RW))
++              return EXT2_ET_RO_FILSYS;
++
++      if ((ino == 0) || (ino > fs->super->s_inodes_count))
++              return EXT2_ET_BAD_INODE_NUM;
++
++      length = bufsize;
++      if (length < EXT2_INODE_SIZE(fs->super))
++              length = EXT2_INODE_SIZE(fs->super);
++
++      if (length > (int) sizeof(struct ext2_inode_large)) {
++              w_inode = malloc(length);
++              if (!w_inode)
++                      return ENOMEM;
++      } else
++              w_inode = &temp_inode;
++      memset(w_inode, 0, length);
++
++#ifdef EXT2FS_ENABLE_SWAPFS
++      if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
++          (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
++              ext2fs_swap_inode_full(fs, w_inode, 
++                                     (struct ext2_inode_large *) inode, 
++                                     1, bufsize);
++      else
++#endif
++              memcpy(w_inode, inode, bufsize);
++      
++      group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
++      offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) *
++              EXT2_INODE_SIZE(fs->super);
++      block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super);
++      if (!fs->group_desc[(unsigned) group].bg_inode_table)
++              return EXT2_ET_MISSING_INODE_TABLE;
++      block_nr = fs->group_desc[(unsigned) group].bg_inode_table + block;
++
++      offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
++
++      length = EXT2_INODE_SIZE(fs->super);
++      if (length > bufsize)
++              length = bufsize;
++
++      ptr = (char *) w_inode;
++
++      while (length) {
++              clen = length;
++              if ((offset + length) > fs->blocksize)
++                      clen = fs->blocksize - offset;
++
++              if (fs->icache->buffer_blk != block_nr) {
++                      retval = io_channel_read_blk(fs->io, block_nr, 1,
++                                                   fs->icache->buffer);
++                      if (retval)
++                              goto errout;
++                      fs->icache->buffer_blk = block_nr;
++              }
++
++      
++              memcpy((char *) fs->icache->buffer + (unsigned) offset, 
++                     ptr, clen);
++
++              retval = io_channel_write_blk(fs->io, block_nr, 1, 
++                                            fs->icache->buffer);
++              if (retval)
++                      goto errout;
++
++              offset = 0;
++              ptr += clen;
++              length -= clen;
++              block_nr++;
++      }
++              
++      fs->flags |= EXT2_FLAG_CHANGED;
++errout:
++      if (w_inode && w_inode != &temp_inode)
++              free(w_inode);
++      return retval;
++}
++
++errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino,
++                           struct ext2_inode *inode)
++{
++      return ext2fs_write_inode_full(fs, ino, inode,
++                                     sizeof(struct ext2_inode));
++}
++
++/* 
++ * This function should be called when writing a new inode.  It makes
++ * sure that extra part of large inodes is initialized properly.
++ */
++errcode_t ext2fs_write_new_inode(ext2_filsys fs, ext2_ino_t ino,
++                               struct ext2_inode *inode)
++{
++      struct ext2_inode       *buf;
++      int                     size = EXT2_INODE_SIZE(fs->super);
++      struct ext2_inode_large *large_inode;
++
++      if (size == sizeof(struct ext2_inode))
++              return ext2fs_write_inode_full(fs, ino, inode,
++                                             sizeof(struct ext2_inode));
++
++      buf = malloc(size);
++      if (!buf)
++              return ENOMEM;
++
++      memset(buf, 0, size);
++      *buf = *inode;
++
++      large_inode = (struct ext2_inode_large *) buf;
++      large_inode->i_extra_isize = sizeof(struct ext2_inode_large) - 
++              EXT2_GOOD_OLD_INODE_SIZE;
++
++      return ext2fs_write_inode_full(fs, ino, buf, size);
++}
++
++ 
++errcode_t ext2fs_get_blocks(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks)
++{
++      struct ext2_inode       inode;
++      int                     i;
++      errcode_t               retval;
++      
++      EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
++
++      if (ino > fs->super->s_inodes_count)
++              return EXT2_ET_BAD_INODE_NUM;
++
++      if (fs->get_blocks) {
++              if (!(*fs->get_blocks)(fs, ino, blocks))
++                      return 0;
++      }
++      retval = ext2fs_read_inode(fs, ino, &inode);
++      if (retval)
++              return retval;
++      for (i=0; i < EXT2_N_BLOCKS; i++)
++              blocks[i] = inode.i_block[i];
++      return 0;
++}
++
++errcode_t ext2fs_check_directory(ext2_filsys fs, ext2_ino_t ino)
++{
++      struct  ext2_inode      inode;
++      errcode_t               retval;
++      
++      EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
++
++      if (ino > fs->super->s_inodes_count)
++              return EXT2_ET_BAD_INODE_NUM;
++
++      if (fs->check_directory) {
++              retval = (fs->check_directory)(fs, ino);
++              if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
++                      return retval;
++      }
++      retval = ext2fs_read_inode(fs, ino, &inode);
++      if (retval)
++              return retval;
++      if (!LINUX_S_ISDIR(inode.i_mode))
++              return EXT2_ET_NO_DIRECTORY;
++      return 0;
++}
++
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/inode_io.c busybox/e2fsprogs/ext2fs/inode_io.c
+--- busybox-1.00/e2fsprogs/ext2fs/inode_io.c   1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/inode_io.c        2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,270 @@
++/*
++ * inode_io.c --- This is allows an inode in an ext2 filesystem image
++ *    to be accessed via the I/O manager interface.
++ *
++ * Copyright (C) 2002 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#if HAVE_ERRNO_H
++#include <errno.h>
++#endif
++#include <time.h>
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++/*
++ * For checking structure magic numbers...
++ */
++
++#define EXT2_CHECK_MAGIC(struct, code) \
++        if ((struct)->magic != (code)) return (code)
++
++struct inode_private_data {
++      int                             magic;
++      char                            name[32];
++      ext2_file_t                     file;
++      ext2_filsys                     fs;
++      ext2_ino_t                      ino;
++      struct ext2_inode               inode;
++      int                             flags;
++      struct inode_private_data       *next;
++};
++
++#define CHANNEL_HAS_INODE     0x8000
++
++static struct inode_private_data *top_intern;
++static int ino_unique = 0;
++
++static errcode_t inode_open(const char *name, int flags, io_channel *channel);
++static errcode_t inode_close(io_channel channel);
++static errcode_t inode_set_blksize(io_channel channel, int blksize);
++static errcode_t inode_read_blk(io_channel channel, unsigned long block,
++                             int count, void *data);
++static errcode_t inode_write_blk(io_channel channel, unsigned long block,
++                              int count, const void *data);
++static errcode_t inode_flush(io_channel channel);
++static errcode_t inode_write_byte(io_channel channel, unsigned long offset,
++                              int size, const void *data);
++
++static struct struct_io_manager struct_inode_manager = {
++      EXT2_ET_MAGIC_IO_MANAGER,
++      "Inode I/O Manager",
++      inode_open,
++      inode_close,
++      inode_set_blksize,
++      inode_read_blk,
++      inode_write_blk,
++      inode_flush,
++      inode_write_byte
++};
++
++io_manager inode_io_manager = &struct_inode_manager;
++
++errcode_t ext2fs_inode_io_intern2(ext2_filsys fs, ext2_ino_t ino,
++                                struct ext2_inode *inode,
++                                char **name)
++{
++      struct inode_private_data       *data;
++      errcode_t                       retval;
++
++      if ((retval = ext2fs_get_mem(sizeof(struct inode_private_data),
++                                   &data)))
++              return retval;
++      data->magic = EXT2_ET_MAGIC_INODE_IO_CHANNEL;
++      sprintf(data->name, "%u:%d", ino, ino_unique++);
++      data->file = 0;
++      data->fs = fs;
++      data->ino = ino;
++      data->flags = 0;
++      if (inode) {
++              memcpy(&data->inode, inode, sizeof(struct ext2_inode));
++              data->flags |= CHANNEL_HAS_INODE;
++      }
++      data->next = top_intern;
++      top_intern = data;
++      *name = data->name;
++      return 0;
++}
++
++errcode_t ext2fs_inode_io_intern(ext2_filsys fs, ext2_ino_t ino,
++                               char **name)
++{
++      return ext2fs_inode_io_intern2(fs, ino, NULL, name);
++}
++
++
++static errcode_t inode_open(const char *name, int flags, io_channel *channel)
++{
++      io_channel      io = NULL;
++      struct inode_private_data *prev, *data = NULL;
++      errcode_t       retval;
++      int             open_flags;
++
++      if (name == 0)
++              return EXT2_ET_BAD_DEVICE_NAME;
++
++      for (data = top_intern, prev = NULL; data;
++           prev = data, data = data->next)
++              if (strcmp(name, data->name) == 0)
++                      break;
++      if (!data)
++              return ENOENT;
++      if (prev)
++              prev->next = data->next;
++      else
++              top_intern = data->next;
++
++      retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
++      if (retval)
++              goto cleanup;
++      memset(io, 0, sizeof(struct struct_io_channel));
++
++      io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
++      io->manager = inode_io_manager;
++      retval = ext2fs_get_mem(strlen(name)+1, &io->name);
++      if (retval)
++              goto cleanup;
++
++      strcpy(io->name, name);
++      io->private_data = data;
++      io->block_size = 1024;
++      io->read_error = 0;
++      io->write_error = 0;
++      io->refcount = 1;
++
++      open_flags = (flags & IO_FLAG_RW) ? EXT2_FILE_WRITE : 0;
++      retval = ext2fs_file_open2(data->fs, data->ino,
++                                 (data->flags & CHANNEL_HAS_INODE) ?
++                                 &data->inode : 0, open_flags,
++                                 &data->file);
++      if (retval)
++              goto cleanup;
++              
++      *channel = io;
++      return 0;
++
++cleanup:
++      if (data) {
++              ext2fs_free_mem(&data);
++      }
++      if (io)
++              ext2fs_free_mem(&io);
++      return retval;
++}
++
++static errcode_t inode_close(io_channel channel)
++{
++      struct inode_private_data *data;
++      errcode_t       retval = 0;
++
++      EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
++      data = (struct inode_private_data *) channel->private_data;
++      EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
++
++      if (--channel->refcount > 0)
++              return 0;
++
++      retval = ext2fs_file_close(data->file);
++      
++      ext2fs_free_mem(&channel->private_data);
++      if (channel->name)
++              ext2fs_free_mem(&channel->name);
++      ext2fs_free_mem(&channel);
++      return retval;
++}
++
++static errcode_t inode_set_blksize(io_channel channel, int blksize)
++{
++      struct inode_private_data *data;
++
++      EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
++      data = (struct inode_private_data *) channel->private_data;
++      EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
++
++      channel->block_size = blksize;
++      return 0;
++}
++
++
++static errcode_t inode_read_blk(io_channel channel, unsigned long block,
++                             int count, void *buf)
++{
++      struct inode_private_data *data;
++      errcode_t       retval;
++
++      EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
++      data = (struct inode_private_data *) channel->private_data;
++      EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
++
++      if ((retval = ext2fs_file_lseek(data->file,
++                                      block * channel->block_size,
++                                      EXT2_SEEK_SET, 0)))
++              return retval;
++
++      count = (count < 0) ? -count : (count * channel->block_size);
++
++      return ext2fs_file_read(data->file, buf, count, 0);
++}
++
++static errcode_t inode_write_blk(io_channel channel, unsigned long block,
++                              int count, const void *buf)
++{
++      struct inode_private_data *data;
++      errcode_t       retval;
++
++      EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
++      data = (struct inode_private_data *) channel->private_data;
++      EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
++
++      if ((retval = ext2fs_file_lseek(data->file,
++                                      block * channel->block_size,
++                                      EXT2_SEEK_SET, 0)))
++              return retval;
++
++      count = (count < 0) ? -count : (count * channel->block_size);
++
++      return ext2fs_file_write(data->file, buf, count, 0);
++}
++
++static errcode_t inode_write_byte(io_channel channel, unsigned long offset,
++                               int size, const void *buf)
++{
++      struct inode_private_data *data;
++      errcode_t       retval = 0;
++
++      EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
++      data = (struct inode_private_data *) channel->private_data;
++      EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
++
++      if ((retval = ext2fs_file_lseek(data->file, offset,
++                                      EXT2_SEEK_SET, 0)))
++              return retval;
++
++      return ext2fs_file_write(data->file, buf, size, 0);
++}
++
++/*
++ * Flush data buffers to disk.  
++ */
++static errcode_t inode_flush(io_channel channel)
++{
++      struct inode_private_data *data;
++      
++      EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
++      data = (struct inode_private_data *) channel->private_data;
++      EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
++
++      return ext2fs_file_flush(data->file);
++}
++
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/io_manager.c busybox/e2fsprogs/ext2fs/io_manager.c
+--- busybox-1.00/e2fsprogs/ext2fs/io_manager.c 1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/io_manager.c      2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,69 @@
++/*
++ * io_manager.c --- the I/O manager abstraction
++ */
++
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <fcntl.h>
++#include <time.h>
++#if HAVE_SYS_STAT_H
++#include <sys/stat.h>
++#endif
++#if HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++errcode_t io_channel_set_options(io_channel channel, const char *opts)
++{
++      errcode_t retval = 0;
++      char *next, *ptr, *options, *arg;
++
++      EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
++
++      if (!opts)
++              return 0;
++
++      if (!channel->manager->set_option)
++              return EXT2_ET_INVALID_ARGUMENT;
++
++      options = malloc(strlen(opts)+1);
++      if (!options)
++              return EXT2_ET_NO_MEMORY;
++      strcpy(options, opts);
++      ptr = options;
++
++      while (ptr && *ptr) {
++              next = strchr(ptr, '&');
++              if (next)
++                      *next++ = 0;
++
++              arg = strchr(ptr, '=');
++              if (arg)
++                      *arg++ = 0;
++
++              retval = (channel->manager->set_option)(channel, ptr, arg);
++              if (retval)
++                      break;
++              ptr = next;
++      }
++      free(options);
++      return retval;
++}
++
++errcode_t io_channel_write_byte(io_channel channel, unsigned long offset,
++                              int count, const void *data)
++{
++      EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
++
++      if (channel->manager->write_byte) 
++              return channel->manager->write_byte(channel, offset, 
++                                                  count, data);
++
++      return EXT2_ET_UNIMPLEMENTED;
++}
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/irel.h busybox/e2fsprogs/ext2fs/irel.h
+--- busybox-1.00/e2fsprogs/ext2fs/irel.h       1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/irel.h    2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,114 @@
++/*
++ * irel.h
++ * 
++ * Copyright (C) 1996, 1997 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++struct ext2_inode_reference {
++      blk_t   block;
++      __u16 offset;
++};
++
++struct ext2_inode_relocate_entry {
++      ext2_ino_t      new;
++      ext2_ino_t      orig;
++      __u16           flags;
++      __u16           max_refs;
++};
++
++typedef struct ext2_inode_relocation_table *ext2_irel;
++
++struct ext2_inode_relocation_table {
++      __u32   magic;
++      char    *name;
++      ext2_ino_t      current;
++      void    *priv_data;
++
++      /*
++       * Add an inode relocation entry.
++       */
++      errcode_t (*put)(ext2_irel irel, ext2_ino_t old,
++                            struct ext2_inode_relocate_entry *ent);
++      /*
++       * Get an inode relocation entry.
++       */
++      errcode_t (*get)(ext2_irel irel, ext2_ino_t old,
++                            struct ext2_inode_relocate_entry *ent);
++
++      /*
++       * Get an inode relocation entry by its original inode number
++       */
++      errcode_t (*get_by_orig)(ext2_irel irel, ext2_ino_t orig, ext2_ino_t *old,
++                               struct ext2_inode_relocate_entry *ent);
++
++      /*
++       * Initialize for iterating over the inode relocation entries.
++       */
++      errcode_t (*start_iter)(ext2_irel irel);
++
++      /*
++       * The iterator function for the inode relocation entries.
++       * Returns an inode number of 0 when out of entries.
++       */
++      errcode_t (*next)(ext2_irel irel, ext2_ino_t *old,
++                        struct ext2_inode_relocate_entry *ent);
++
++      /*
++       * Add an inode reference (i.e., note the fact that a
++       * particular block/offset contains a reference to an inode)
++       */
++      errcode_t (*add_ref)(ext2_irel irel, ext2_ino_t ino,
++                           struct ext2_inode_reference *ref);
++
++      /*
++       * Initialize for iterating over the inode references for a
++       * particular inode.
++       */
++      errcode_t (*start_iter_ref)(ext2_irel irel, ext2_ino_t ino);
++
++      /*
++       * The iterator function for the inode references for an
++       * inode.  The references for only one inode can be interator
++       * over at a time, as the iterator state is stored in ext2_irel.
++       */
++      errcode_t (*next_ref)(ext2_irel irel,
++                            struct ext2_inode_reference *ref);
++
++      /*
++       * Move the inode relocation table from one inode number to
++       * another.  Note that the inode references also must move.
++       */
++      errcode_t (*move)(ext2_irel irel, ext2_ino_t old, ext2_ino_t new);
++
++      /*
++       * Remove an inode relocation entry, along with all of the
++       * inode references.
++       */
++      errcode_t (*delete)(ext2_irel irel, ext2_ino_t old);
++
++      /*
++       * Free the inode relocation table.
++       */
++      errcode_t (*free)(ext2_irel irel);
++};
++
++errcode_t ext2fs_irel_memarray_create(char *name, ext2_ino_t max_inode,
++                                  ext2_irel *irel);
++
++#define ext2fs_irel_put(irel, old, ent) ((irel)->put((irel), old, ent))
++#define ext2fs_irel_get(irel, old, ent) ((irel)->get((irel), old, ent))
++#define ext2fs_irel_get_by_orig(irel, orig, old, ent) \
++                      ((irel)->get_by_orig((irel), orig, old, ent))
++#define ext2fs_irel_start_iter(irel) ((irel)->start_iter((irel)))
++#define ext2fs_irel_next(irel, old, ent) ((irel)->next((irel), old, ent))
++#define ext2fs_irel_add_ref(irel, ino, ref) ((irel)->add_ref((irel), ino, ref))
++#define ext2fs_irel_start_iter_ref(irel, ino) ((irel)->start_iter_ref((irel), ino))
++#define ext2fs_irel_next_ref(irel, ref) ((irel)->next_ref((irel), ref))
++#define ext2fs_irel_move(irel, old, new) ((irel)->move((irel), old, new))
++#define ext2fs_irel_delete(irel, old) ((irel)->delete((irel), old))
++#define ext2fs_irel_free(irel) ((irel)->free((irel)))
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/irel_ma.c busybox/e2fsprogs/ext2fs/irel_ma.c
+--- busybox-1.00/e2fsprogs/ext2fs/irel_ma.c    1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/irel_ma.c 2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,372 @@
++/*
++ * irel_ma.c
++ * 
++ * Copyright (C) 1996, 1997 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <fcntl.h>
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#if HAVE_ERRNO_H
++#include <errno.h>
++#endif
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++#include "irel.h"
++
++static errcode_t ima_put(ext2_irel irel, ext2_ino_t old,
++                       struct ext2_inode_relocate_entry *ent);
++static errcode_t ima_get(ext2_irel irel, ext2_ino_t old,
++                       struct ext2_inode_relocate_entry *ent);
++static errcode_t ima_get_by_orig(ext2_irel irel, ext2_ino_t orig, ext2_ino_t *old,
++                               struct ext2_inode_relocate_entry *ent);
++static errcode_t ima_start_iter(ext2_irel irel);
++static errcode_t ima_next(ext2_irel irel, ext2_ino_t *old,
++                        struct ext2_inode_relocate_entry *ent);
++static errcode_t ima_add_ref(ext2_irel irel, ext2_ino_t ino,
++                           struct ext2_inode_reference *ref);
++static errcode_t ima_start_iter_ref(ext2_irel irel, ext2_ino_t ino);
++static errcode_t ima_next_ref(ext2_irel irel, struct ext2_inode_reference *ref);
++static errcode_t ima_move(ext2_irel irel, ext2_ino_t old, ext2_ino_t new);
++static errcode_t ima_delete(ext2_irel irel, ext2_ino_t old);
++static errcode_t ima_free(ext2_irel irel);
++
++/*
++ * This data structure stores the array of inode references; there is
++ * a structure for each inode.
++ */
++struct inode_reference_entry {
++      __u16 num;
++      struct ext2_inode_reference *refs;
++};
++
++struct irel_ma {
++      __u32 magic;
++      ext2_ino_t max_inode;
++      ext2_ino_t ref_current;
++      int   ref_iter;
++      ext2_ino_t      *orig_map;
++      struct ext2_inode_relocate_entry *entries;
++      struct inode_reference_entry *ref_entries;
++};
++
++errcode_t ext2fs_irel_memarray_create(char *name, ext2_ino_t max_inode,
++                                    ext2_irel *new_irel)
++{
++      ext2_irel               irel = 0;
++      errcode_t       retval;
++      struct irel_ma  *ma = 0;
++      size_t          size;
++
++      *new_irel = 0;
++
++      /*
++       * Allocate memory structures
++       */
++      retval = ext2fs_get_mem(sizeof(struct ext2_inode_relocation_table),
++                              &irel);
++      if (retval)
++              goto errout;
++      memset(irel, 0, sizeof(struct ext2_inode_relocation_table));
++      
++      retval = ext2fs_get_mem(strlen(name)+1, &irel->name);
++      if (retval)
++              goto errout;
++      strcpy(irel->name, name);
++      
++      retval = ext2fs_get_mem(sizeof(struct irel_ma), &ma);
++      if (retval)
++              goto errout;
++      memset(ma, 0, sizeof(struct irel_ma));
++      irel->priv_data = ma;
++      
++      size = (size_t) (sizeof(ext2_ino_t) * (max_inode+1));
++      retval = ext2fs_get_mem(size, &ma->orig_map);
++      if (retval)
++              goto errout;
++      memset(ma->orig_map, 0, size);
++
++      size = (size_t) (sizeof(struct ext2_inode_relocate_entry) *
++                       (max_inode+1));
++      retval = ext2fs_get_mem(size, &ma->entries);
++      if (retval)
++              goto errout;
++      memset(ma->entries, 0, size);
++
++      size = (size_t) (sizeof(struct inode_reference_entry) *
++                       (max_inode+1));
++      retval = ext2fs_get_mem(size, &ma->ref_entries);
++      if (retval)
++              goto errout;
++      memset(ma->ref_entries, 0, size);
++      ma->max_inode = max_inode;
++
++      /*
++       * Fill in the irel data structure
++       */
++      irel->put = ima_put;
++      irel->get = ima_get;
++      irel->get_by_orig = ima_get_by_orig;
++      irel->start_iter = ima_start_iter;
++      irel->next = ima_next;
++      irel->add_ref = ima_add_ref;
++      irel->start_iter_ref = ima_start_iter_ref;
++      irel->next_ref = ima_next_ref;
++      irel->move = ima_move;
++      irel->delete = ima_delete;
++      irel->free = ima_free;
++      
++      *new_irel = irel;
++      return 0;
++
++errout:
++      ima_free(irel);
++      return retval;
++}
++
++static errcode_t ima_put(ext2_irel irel, ext2_ino_t old,
++                      struct ext2_inode_relocate_entry *ent)
++{
++      struct inode_reference_entry    *ref_ent;
++      struct irel_ma                  *ma;
++      errcode_t                       retval;
++      size_t                          size, old_size;
++
++      ma = irel->priv_data;
++      if (old > ma->max_inode)
++              return EXT2_ET_INVALID_ARGUMENT;
++
++      /*
++       * Force the orig field to the correct value; the application
++       * program shouldn't be messing with this field.
++       */
++      if (ma->entries[(unsigned) old].new == 0)
++              ent->orig = old;
++      else
++              ent->orig = ma->entries[(unsigned) old].orig;
++      
++      /*
++       * If max_refs has changed, reallocate the refs array
++       */
++      ref_ent = ma->ref_entries + (unsigned) old;
++      if (ref_ent->refs && ent->max_refs !=
++          ma->entries[(unsigned) old].max_refs) {
++              size = (sizeof(struct ext2_inode_reference) * ent->max_refs);
++              old_size = (sizeof(struct ext2_inode_reference) *
++                          ma->entries[(unsigned) old].max_refs);
++              retval = ext2fs_resize_mem(old_size, size, &ref_ent->refs);
++              if (retval)
++                      return retval;
++      }
++
++      ma->entries[(unsigned) old] = *ent;
++      ma->orig_map[(unsigned) ent->orig] = old;
++      return 0;
++}
++
++static errcode_t ima_get(ext2_irel irel, ext2_ino_t old,
++                      struct ext2_inode_relocate_entry *ent)
++{
++      struct irel_ma  *ma;
++
++      ma = irel->priv_data;
++      if (old > ma->max_inode)
++              return EXT2_ET_INVALID_ARGUMENT;
++      if (ma->entries[(unsigned) old].new == 0)
++              return ENOENT;
++      *ent = ma->entries[(unsigned) old];
++      return 0;
++}
++
++static errcode_t ima_get_by_orig(ext2_irel irel, ext2_ino_t orig, ext2_ino_t *old,
++                      struct ext2_inode_relocate_entry *ent)
++{
++      struct irel_ma  *ma;
++      ext2_ino_t      ino;
++
++      ma = irel->priv_data;
++      if (orig > ma->max_inode)
++              return EXT2_ET_INVALID_ARGUMENT;
++      ino = ma->orig_map[(unsigned) orig];
++      if (ino == 0)
++              return ENOENT;
++      *old = ino;
++      *ent = ma->entries[(unsigned) ino];
++      return 0;
++}
++
++static errcode_t ima_start_iter(ext2_irel irel)
++{
++      irel->current = 0;
++      return 0;
++}
++
++static errcode_t ima_next(ext2_irel irel, ext2_ino_t *old,
++                       struct ext2_inode_relocate_entry *ent)
++{
++      struct irel_ma  *ma;
++
++      ma = irel->priv_data;
++      while (++irel->current < ma->max_inode) {
++              if (ma->entries[(unsigned) irel->current].new == 0)
++                      continue;
++              *old = irel->current;
++              *ent = ma->entries[(unsigned) irel->current];
++              return 0;
++      }
++      *old = 0;
++      return 0;
++}
++
++static errcode_t ima_add_ref(ext2_irel irel, ext2_ino_t ino,
++                           struct ext2_inode_reference *ref)
++{
++      struct irel_ma  *ma;
++      size_t          size;
++      struct inode_reference_entry *ref_ent;
++      struct ext2_inode_relocate_entry *ent;
++      errcode_t               retval;
++
++      ma = irel->priv_data;
++      if (ino > ma->max_inode)
++              return EXT2_ET_INVALID_ARGUMENT;
++
++      ref_ent = ma->ref_entries + (unsigned) ino;
++      ent = ma->entries + (unsigned) ino;
++      
++      /*
++       * If the inode reference array doesn't exist, create it.
++       */
++      if (ref_ent->refs == 0) {
++              size = (size_t) ((sizeof(struct ext2_inode_reference) * 
++                                ent->max_refs));
++              retval = ext2fs_get_mem(size, &ref_ent->refs);
++              if (retval)
++                      return retval;
++              memset(ref_ent->refs, 0, size);
++              ref_ent->num = 0;
++      }
++
++      if (ref_ent->num >= ent->max_refs)
++              return EXT2_ET_TOO_MANY_REFS;
++
++      ref_ent->refs[(unsigned) ref_ent->num++] = *ref;
++      return 0;
++}
++
++static errcode_t ima_start_iter_ref(ext2_irel irel, ext2_ino_t ino)
++{
++      struct irel_ma  *ma;
++
++      ma = irel->priv_data;
++      if (ino > ma->max_inode)
++              return EXT2_ET_INVALID_ARGUMENT;
++      if (ma->entries[(unsigned) ino].new == 0)
++              return ENOENT;
++      ma->ref_current = ino;
++      ma->ref_iter = 0;
++      return 0;
++}
++
++static errcode_t ima_next_ref(ext2_irel irel,
++                            struct ext2_inode_reference *ref)
++{
++      struct irel_ma  *ma;
++      struct inode_reference_entry *ref_ent;
++
++      ma = irel->priv_data;
++      
++      ref_ent = ma->ref_entries + ma->ref_current;
++
++      if ((ref_ent->refs == NULL) ||
++          (ma->ref_iter >= ref_ent->num)) {
++              ref->block = 0;
++              ref->offset = 0;
++              return 0;
++      }
++      *ref = ref_ent->refs[ma->ref_iter++];
++      return 0;
++}
++
++
++static errcode_t ima_move(ext2_irel irel, ext2_ino_t old, ext2_ino_t new)
++{
++      struct irel_ma  *ma;
++
++      ma = irel->priv_data;
++      if ((old > ma->max_inode) || (new > ma->max_inode))
++              return EXT2_ET_INVALID_ARGUMENT;
++      if (ma->entries[(unsigned) old].new == 0)
++              return ENOENT;
++      
++      ma->entries[(unsigned) new] = ma->entries[(unsigned) old];
++      if (ma->ref_entries[(unsigned) new].refs)
++              ext2fs_free_mem(&ma->ref_entries[(unsigned) new].refs);
++      ma->ref_entries[(unsigned) new] = ma->ref_entries[(unsigned) old];
++      
++      ma->entries[(unsigned) old].new = 0;
++      ma->ref_entries[(unsigned) old].num = 0;
++      ma->ref_entries[(unsigned) old].refs = 0;
++
++      ma->orig_map[ma->entries[new].orig] = new;
++      return 0;
++}
++
++static errcode_t ima_delete(ext2_irel irel, ext2_ino_t old)
++{
++      struct irel_ma  *ma;
++
++      ma = irel->priv_data;
++      if (old > ma->max_inode)
++              return EXT2_ET_INVALID_ARGUMENT;
++      if (ma->entries[(unsigned) old].new == 0)
++              return ENOENT;
++      
++      ma->entries[old].new = 0;
++      if (ma->ref_entries[(unsigned) old].refs)
++              ext2fs_free_mem(&ma->ref_entries[(unsigned) old].refs);
++      ma->orig_map[ma->entries[(unsigned) old].orig] = 0;
++      
++      ma->ref_entries[(unsigned) old].num = 0;
++      ma->ref_entries[(unsigned) old].refs = 0;
++      return 0;
++}
++
++static errcode_t ima_free(ext2_irel irel)
++{
++      struct irel_ma  *ma;
++      ext2_ino_t      ino;
++
++      if (!irel)
++              return 0;
++
++      ma = irel->priv_data;
++
++      if (ma) {
++              if (ma->orig_map)
++                      ext2fs_free_mem(&ma->orig_map);
++              if (ma->entries)
++                      ext2fs_free_mem(&ma->entries);
++              if (ma->ref_entries) {
++                      for (ino = 0; ino <= ma->max_inode; ino++) {
++                              if (ma->ref_entries[(unsigned) ino].refs)
++                                      ext2fs_free_mem(&ma->ref_entries[(unsigned) ino].refs);
++                      }
++                      ext2fs_free_mem(&ma->ref_entries);
++              }
++              ext2fs_free_mem(&ma);
++      }
++      if (irel->name)
++              ext2fs_free_mem(&irel->name);
++      ext2fs_free_mem(&irel);
++      return 0;
++}
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/ismounted.c busybox/e2fsprogs/ext2fs/ismounted.c
+--- busybox-1.00/e2fsprogs/ext2fs/ismounted.c  1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/ismounted.c       2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,358 @@
++/*
++ * ismounted.c --- Check to see if the filesystem was mounted
++ * 
++ * Copyright (C) 1995,1996,1997,1998,1999,2000 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#if HAVE_ERRNO_H
++#include <errno.h>
++#endif
++#include <fcntl.h>
++#ifdef HAVE_LINUX_FD_H
++#include <linux/fd.h>
++#endif
++#ifdef HAVE_MNTENT_H
++#include <mntent.h>
++#endif
++#ifdef HAVE_GETMNTINFO
++#include <paths.h>
++#include <sys/param.h>
++#include <sys/mount.h>
++#endif /* HAVE_GETMNTINFO */
++#include <string.h>
++#include <sys/stat.h>
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++#ifdef HAVE_MNTENT_H
++/*
++ * Helper function which checks a file in /etc/mtab format to see if a
++ * filesystem is mounted.  Returns an error if the file doesn't exist
++ * or can't be opened.  
++ */
++static errcode_t check_mntent_file(const char *mtab_file, const char *file, 
++                                 int *mount_flags, char *mtpt, int mtlen)
++{
++      struct mntent   *mnt;
++      struct stat     st_buf;
++      errcode_t       retval = 0;
++      dev_t           file_dev=0, file_rdev=0;
++      ino_t           file_ino=0;
++      FILE            *f;
++      int             fd;
++
++      *mount_flags = 0;
++      if ((f = setmntent (mtab_file, "r")) == NULL)
++              return errno;
++      if (stat(file, &st_buf) == 0) {
++              if (S_ISBLK(st_buf.st_mode)) {
++#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */
++                      file_rdev = st_buf.st_rdev;
++#endif        /* __GNU__ */
++              } else {
++                      file_dev = st_buf.st_dev;
++                      file_ino = st_buf.st_ino;
++              }
++      }
++      while ((mnt = getmntent (f)) != NULL) {
++              if (strcmp(file, mnt->mnt_fsname) == 0)
++                      break;
++              if (stat(mnt->mnt_fsname, &st_buf) == 0) {
++                      if (S_ISBLK(st_buf.st_mode)) {
++#ifndef __GNU__
++                              if (file_rdev && (file_rdev == st_buf.st_rdev))
++                                      break;
++#endif        /* __GNU__ */
++                      } else {
++                              if (file_dev && ((file_dev == st_buf.st_dev) &&
++                                               (file_ino == st_buf.st_ino)))
++                                      break;
++                      }
++              }
++      }
++
++      if (mnt == 0) {
++#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */
++              /*
++               * Do an extra check to see if this is the root device.  We
++               * can't trust /etc/mtab, and /proc/mounts will only list
++               * /dev/root for the root filesystem.  Argh.  Instead we
++               * check if the given device has the same major/minor number
++               * as the device that the root directory is on.
++               */
++              if (file_rdev && stat("/", &st_buf) == 0) {
++                      if (st_buf.st_dev == file_rdev) {
++                              *mount_flags = EXT2_MF_MOUNTED;
++                              if (mtpt)
++                                      strncpy(mtpt, "/", mtlen);
++                              goto is_root;
++                      }
++              }
++#endif        /* __GNU__ */
++              goto errout;
++      }
++#ifndef __GNU__ /* The GNU hurd is deficient; what else is new? */
++      /* Validate the entry in case /etc/mtab is out of date */
++      /* 
++       * We need to be paranoid, because some broken distributions
++       * (read: Slackware) don't initialize /etc/mtab before checking
++       * all of the non-root filesystems on the disk.
++       */
++      if (stat(mnt->mnt_dir, &st_buf) < 0) {
++              retval = errno;
++              if (retval == ENOENT) {
++#ifdef DEBUG
++                      printf("Bogus entry in %s!  (%s does not exist)\n",
++                             mtab_file, mnt->mnt_dir);
++#endif /* DEBUG */
++                      retval = 0;
++              }
++              goto errout;
++      }
++      if (file_rdev && (st_buf.st_dev != file_rdev)) {
++#ifdef DEBUG
++              printf("Bogus entry in %s!  (%s not mounted on %s)\n",
++                     mtab_file, file, mnt->mnt_dir);
++#endif /* DEBUG */
++              goto errout;
++      }
++#endif /* __GNU__ */
++      *mount_flags = EXT2_MF_MOUNTED;
++      
++#ifdef MNTOPT_RO
++      /* Check to see if the ro option is set */
++      if (hasmntopt(mnt, MNTOPT_RO))
++              *mount_flags |= EXT2_MF_READONLY;
++#endif
++
++      if (mtpt)
++              strncpy(mtpt, mnt->mnt_dir, mtlen);
++      /*
++       * Check to see if we're referring to the root filesystem.
++       * If so, do a manual check to see if we can open /etc/mtab
++       * read/write, since if the root is mounted read/only, the
++       * contents of /etc/mtab may not be accurate.
++       */
++      if (!strcmp(mnt->mnt_dir, "/")) {
++is_root:
++#define TEST_FILE "/.ismount-test-file"               
++              *mount_flags |= EXT2_MF_ISROOT;
++              fd = open(TEST_FILE, O_RDWR|O_CREAT);
++              if (fd < 0) {
++                      if (errno == EROFS)
++                              *mount_flags |= EXT2_MF_READONLY;
++              } else
++                      close(fd);
++              (void) unlink(TEST_FILE);
++      }
++      retval = 0;
++errout:
++      endmntent (f);
++      return retval;
++}
++
++static errcode_t check_mntent(const char *file, int *mount_flags,
++                            char *mtpt, int mtlen)
++{
++      errcode_t       retval;
++
++#ifdef DEBUG
++      retval = check_mntent_file("/tmp/mtab", file, mount_flags,
++                                 mtpt, mtlen);
++      if (retval == 0)
++              return 0;
++#endif /* DEBUG */
++#ifdef __linux__
++      retval = check_mntent_file("/proc/mounts", file, mount_flags,
++                                 mtpt, mtlen);
++      if (retval == 0 && (*mount_flags != 0))
++              return 0;
++#endif /* __linux__ */
++#if defined(MOUNTED) || defined(_PATH_MOUNTED)
++#ifndef MOUNTED
++#define MOUNTED _PATH_MOUNTED
++#endif /* MOUNTED */
++      retval = check_mntent_file(MOUNTED, file, mount_flags, mtpt, mtlen);
++      return retval;
++#else 
++      *mount_flags = 0;
++      return 0;
++#endif /* defined(MOUNTED) || defined(_PATH_MOUNTED) */
++}
++
++#else
++#if defined(HAVE_GETMNTINFO)
++
++static errcode_t check_getmntinfo(const char *file, int *mount_flags,
++                                char *mtpt, int mtlen)
++{
++      struct statfs *mp;
++        int    len, n;
++        const  char   *s1;
++      char    *s2;
++
++        n = getmntinfo(&mp, MNT_NOWAIT);
++        if (n == 0)
++              return errno;
++
++        len = sizeof(_PATH_DEV) - 1;
++        s1 = file;
++        if (strncmp(_PATH_DEV, s1, len) == 0)
++                s1 += len;
++ 
++      *mount_flags = 0;
++        while (--n >= 0) {
++                s2 = mp->f_mntfromname;
++                if (strncmp(_PATH_DEV, s2, len) == 0) {
++                        s2 += len - 1;
++                        *s2 = 'r';
++                }
++                if (strcmp(s1, s2) == 0 || strcmp(s1, &s2[1]) == 0) {
++                      *mount_flags = EXT2_MF_MOUNTED;
++                      break;
++              }
++                ++mp;
++      }
++      if (mtpt)
++              strncpy(mtpt, mp->f_mntonname, mtlen);
++      return 0;
++}
++#endif /* HAVE_GETMNTINFO */
++#endif /* HAVE_MNTENT_H */
++
++/*
++ * Check to see if we're dealing with the swap device.
++ */
++static int is_swap_device(const char *file)
++{
++      FILE            *f;
++      char            buf[1024], *cp;
++      dev_t           file_dev;
++      struct stat     st_buf;
++      int             ret = 0;
++
++      file_dev = 0;
++#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */
++      if ((stat(file, &st_buf) == 0) &&
++          S_ISBLK(st_buf.st_mode))
++              file_dev = st_buf.st_rdev;
++#endif        /* __GNU__ */
++
++      if (!(f = fopen("/proc/swaps", "r")))
++              return 0;
++      /* Skip the first line */
++      fgets(buf, sizeof(buf), f);
++      while (!feof(f)) {
++              if (!fgets(buf, sizeof(buf), f))
++                      break;
++              if ((cp = strchr(buf, ' ')) != NULL)
++                      *cp = 0;
++              if ((cp = strchr(buf, '\t')) != NULL)
++                      *cp = 0;
++              if (strcmp(buf, file) == 0) {
++                      ret++;
++                      break;
++              }
++#ifndef __GNU__
++              if (file_dev && (stat(buf, &st_buf) == 0) &&
++                  S_ISBLK(st_buf.st_mode) &&
++                  file_dev == st_buf.st_rdev) {
++                      ret++;
++                      break;
++              }
++#endif        /* __GNU__ */
++      }
++      fclose(f);
++      return ret;
++}
++
++
++/*
++ * ext2fs_check_mount_point() returns 1 if the device is mounted, 0
++ * otherwise.  If mtpt is non-NULL, the directory where the device is
++ * mounted is copied to where mtpt is pointing, up to mtlen
++ * characters.
++ */
++#ifdef __TURBOC__
++ #pragma argsused
++#endif
++errcode_t ext2fs_check_mount_point(const char *device, int *mount_flags,
++                                char *mtpt, int mtlen)
++{
++      if (is_swap_device(device)) {
++              *mount_flags = EXT2_MF_MOUNTED | EXT2_MF_SWAP;
++              strncpy(mtpt, "<swap>", mtlen);
++              return 0;
++      }
++#ifdef HAVE_MNTENT_H
++      return check_mntent(device, mount_flags, mtpt, mtlen);
++#else 
++#ifdef HAVE_GETMNTINFO
++      return check_getmntinfo(device, mount_flags, mtpt, mtlen);
++#else
++#ifdef __GNUC__
++ #warning "Can't use getmntent or getmntinfo to check for mounted filesystems!"
++#endif
++      *mount_flags = 0;
++      return 0;
++#endif /* HAVE_GETMNTINFO */
++#endif /* HAVE_MNTENT_H */
++}
++
++/*
++ * ext2fs_check_if_mounted() sets the mount_flags EXT2_MF_MOUNTED,
++ * EXT2_MF_READONLY, and EXT2_MF_ROOT
++ * 
++ */
++errcode_t ext2fs_check_if_mounted(const char *file, int *mount_flags)
++{
++      return ext2fs_check_mount_point(file, mount_flags, NULL, 0);
++}
++
++#ifdef DEBUG
++int main(int argc, char **argv)
++{
++      int     retval, mount_flags;
++      char    mntpt[80];
++      
++      if (argc < 2) {
++              fprintf(stderr, "Usage: %s device\n", argv[0]);
++              exit(1);
++      }
++
++      mntpt[0] = 0;
++      retval = ext2fs_check_mount_point(argv[1], &mount_flags,
++                                        mntpt, sizeof(mntpt));
++      if (retval) {
++              com_err(argv[0], retval,
++                      "while calling ext2fs_check_if_mounted");
++              exit(1);
++      }
++      printf("Device %s reports flags %02x\n", argv[1], mount_flags);
++      if (mount_flags & EXT2_MF_MOUNTED)
++              printf("\t%s is mounted.\n", argv[1]);
++
++      if (mount_flags & EXT2_MF_SWAP)
++              printf("\t%s is a swap device.\n", argv[1]);
++
++      if (mount_flags & EXT2_MF_READONLY)
++              printf("\t%s is read-only.\n", argv[1]);
++      
++      if (mount_flags & EXT2_MF_ISROOT)
++              printf("\t%s is the root filesystem.\n", argv[1]);
++      if (mntpt[0])
++              printf("\t%s is mounted on %s.\n", argv[1], mntpt);
++      
++      exit(0);
++}
++#endif /* DEBUG */
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/jfs_compat.h busybox/e2fsprogs/ext2fs/jfs_compat.h
+--- busybox-1.00/e2fsprogs/ext2fs/jfs_compat.h 1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/jfs_compat.h      2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,67 @@
++
++#ifndef _JFS_COMPAT_H
++#define _JFS_COMPAT_H
++
++#include "kernel-list.h"
++#include <errno.h>
++#ifdef HAVE_NETINET_IN_H
++#include <netinet/in.h>
++#endif
++
++#define printk printf
++#define KERN_ERR ""
++#define KERN_DEBUG ""
++
++#define READ 0
++#define WRITE 1
++
++#define cpu_to_be32(n) htonl(n)
++#define be32_to_cpu(n) ntohl(n)
++
++typedef unsigned int tid_t;
++typedef struct journal_s journal_t;
++
++struct buffer_head;
++struct inode;
++
++struct journal_s
++{
++      unsigned long           j_flags;
++      int                     j_errno;
++      struct buffer_head *    j_sb_buffer;
++      struct journal_superblock_s *j_superblock;
++      int                     j_format_version;
++      unsigned long           j_head;
++      unsigned long           j_tail;
++      unsigned long           j_free;
++      unsigned long           j_first, j_last;
++      kdev_t                  j_dev;
++      kdev_t                  j_fs_dev;
++      int                     j_blocksize;
++      unsigned int            j_blk_offset;
++      unsigned int            j_maxlen;
++      struct inode *          j_inode;
++      tid_t                   j_tail_sequence;
++      tid_t                   j_transaction_sequence;
++      __u8                    j_uuid[16];
++      struct jbd_revoke_table_s *j_revoke;
++};
++
++#define J_ASSERT(assert)                                              \
++      do { if (!(assert)) {                                           \
++              printf ("Assertion failure in %s() at %s line %d: "     \
++                      "\"%s\"\n",                                     \
++                      __FUNCTION__, __FILE__, __LINE__, # assert);    \
++              fatal_error(e2fsck_global_ctx, 0);                      \
++      } } while (0)
++
++#define is_journal_abort(x) 0
++
++#define BUFFER_TRACE(bh, info)        do {} while (0)
++
++/* Need this so we can compile with configure --enable-gcc-wall */
++#ifdef NO_INLINE_FUNCS
++#define inline
++#endif
++
++#endif /* _JFS_COMPAT_H */
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/jfs_dat.h busybox/e2fsprogs/ext2fs/jfs_dat.h
+--- busybox-1.00/e2fsprogs/ext2fs/jfs_dat.h    1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/jfs_dat.h 2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,64 @@
++/*
++ * jfs_dat.h --- stripped down header file which only contains the JFS
++ *    on-disk data structures
++ */
++
++#define JFS_MAGIC_NUMBER 0xc03b3998U /* The first 4 bytes of /dev/random! */
++
++/*
++ * On-disk structures
++ */
++
++/* 
++ * Descriptor block types:
++ */
++
++#define JFS_DESCRIPTOR_BLOCK  1
++#define JFS_COMMIT_BLOCK      2
++#define JFS_SUPERBLOCK                3
++
++/*
++ * Standard header for all descriptor blocks:
++ */
++typedef struct journal_header_s
++{
++      __u32           h_magic;
++      __u32           h_blocktype;
++      __u32           h_sequence;
++} journal_header_t;
++
++
++/* 
++ * The block tag: used to describe a single buffer in the journal 
++ */
++typedef struct journal_block_tag_s
++{
++      __u32           t_blocknr;      /* The on-disk block number */
++      __u32           t_flags;        /* See below */
++} journal_block_tag_t;
++
++/* Definitions for the journal tag flags word: */
++#define JFS_FLAG_ESCAPE               1       /* on-disk block is escaped */
++#define JFS_FLAG_SAME_UUID    2       /* block has same uuid as previous */
++#define JFS_FLAG_DELETED      4       /* block deleted by this transaction */
++#define JFS_FLAG_LAST_TAG     8       /* last tag in this descriptor block */
++
++
++/*
++ * The journal superblock
++ */
++typedef struct journal_superblock_s
++{
++      journal_header_t s_header;
++
++      /* Static information describing the journal */
++      __u32           s_blocksize;    /* journal device blocksize */
++      __u32           s_maxlen;       /* total blocks in journal file */
++      __u32           s_first;        /* first block of log information */
++      
++      /* Dynamic information describing the current state of the log */
++      __u32           s_sequence;     /* first commit ID expected in log */
++      __u32           s_start;        /* blocknr of start of log */
++      
++} journal_superblock_t;
++
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/jfs_user.h busybox/e2fsprogs/ext2fs/jfs_user.h
+--- busybox-1.00/e2fsprogs/ext2fs/jfs_user.h   1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/jfs_user.h        2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,8 @@
++#ifndef _JFS_USER_H
++#define _JFS_USER_H
++
++typedef unsigned short kdev_t;
++
++#include "kernel-jbd.h"
++
++#endif /* _JFS_USER_H */
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/kernel-jbd.h busybox/e2fsprogs/ext2fs/kernel-jbd.h
+--- busybox-1.00/e2fsprogs/ext2fs/kernel-jbd.h 1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/kernel-jbd.h      2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,910 @@
++/*
++ * linux/include/linux/jbd.h
++ * 
++ * Written by Stephen C. Tweedie <sct@redhat.com>
++ *
++ * Copyright 1998-2000 Red Hat, Inc --- All Rights Reserved
++ *
++ * This file is part of the Linux kernel and is made available under
++ * the terms of the GNU General Public License, version 2, or at your
++ * option, any later version, incorporated herein by reference.
++ *
++ * Definitions for transaction data structures for the buffer cache
++ * filesystem journaling support.
++ */
++
++#ifndef _LINUX_JBD_H
++#define _LINUX_JBD_H
++
++#if defined(CONFIG_JBD) || defined(CONFIG_JBD_MODULE) || !defined(__KERNEL__)
++
++/* Allow this file to be included directly into e2fsprogs */
++#ifndef __KERNEL__
++#include "jfs_compat.h"
++#define JFS_DEBUG
++#define jfs_debug jbd_debug
++#else
++
++#include <linux/journal-head.h>
++#include <linux/stddef.h>
++#include <asm/semaphore.h>
++#endif
++
++#ifndef __GNUC__
++#define __FUNCTION__ ""
++#endif
++
++#define journal_oom_retry 1
++
++#ifdef __STDC__
++#ifdef __CONFIG_JBD_DEBUG__E2FS
++/*
++ * Define JBD_EXPENSIVE_CHECKING to enable more expensive internal
++ * consistency checks.  By default we don't do this unless
++ * __CONFIG_JBD_DEBUG__E2FS is on.
++ */
++#define JBD_EXPENSIVE_CHECKING
++extern int journal_enable_debug;
++
++#define jbd_debug(n, f, a...)                                         \
++      do {                                                            \
++              if ((n) <= journal_enable_debug) {                      \
++                      printk (KERN_DEBUG "(%s, %d): %s: ",            \
++                              __FILE__, __LINE__, __FUNCTION__);      \
++                      printk (f, ## a);                               \
++              }                                                       \
++      } while (0)
++#else
++#ifdef __GNUC__
++#define jbd_debug(f, a...)    /**/
++#else
++#define jbd_debug(f, ...)     /**/
++#endif        
++#endif
++#else
++#define jbd_debug(x)          /* AIX doesn't do STDC */
++#endif
++
++extern void * __jbd_kmalloc (char *where, size_t size, int flags, int retry);
++#define jbd_kmalloc(size, flags) \
++      __jbd_kmalloc(__FUNCTION__, (size), (flags), journal_oom_retry)
++#define jbd_rep_kmalloc(size, flags) \
++      __jbd_kmalloc(__FUNCTION__, (size), (flags), 1)
++
++#define JFS_MIN_JOURNAL_BLOCKS 1024
++
++#ifdef __KERNEL__
++typedef struct handle_s               handle_t;       /* Atomic operation type */
++typedef struct journal_s      journal_t;      /* Journal control structure */
++#endif
++
++/*
++ * Internal structures used by the logging mechanism:
++ */
++
++#define JFS_MAGIC_NUMBER 0xc03b3998U /* The first 4 bytes of /dev/random! */
++
++/*
++ * On-disk structures
++ */
++
++/* 
++ * Descriptor block types:
++ */
++
++#define JFS_DESCRIPTOR_BLOCK  1
++#define JFS_COMMIT_BLOCK      2
++#define JFS_SUPERBLOCK_V1     3
++#define JFS_SUPERBLOCK_V2     4
++#define JFS_REVOKE_BLOCK      5
++
++/*
++ * Standard header for all descriptor blocks:
++ */
++typedef struct journal_header_s
++{
++      __u32           h_magic;
++      __u32           h_blocktype;
++      __u32           h_sequence;
++} journal_header_t;
++
++
++/* 
++ * The block tag: used to describe a single buffer in the journal 
++ */
++typedef struct journal_block_tag_s
++{
++      __u32           t_blocknr;      /* The on-disk block number */
++      __u32           t_flags;        /* See below */
++} journal_block_tag_t;
++
++/* 
++ * The revoke descriptor: used on disk to describe a series of blocks to
++ * be revoked from the log 
++ */
++typedef struct journal_revoke_header_s
++{
++      journal_header_t r_header;
++      int              r_count;       /* Count of bytes used in the block */
++} journal_revoke_header_t;
++
++
++/* Definitions for the journal tag flags word: */
++#define JFS_FLAG_ESCAPE               1       /* on-disk block is escaped */
++#define JFS_FLAG_SAME_UUID    2       /* block has same uuid as previous */
++#define JFS_FLAG_DELETED      4       /* block deleted by this transaction */
++#define JFS_FLAG_LAST_TAG     8       /* last tag in this descriptor block */
++
++
++/*
++ * The journal superblock.  All fields are in big-endian byte order.
++ */
++typedef struct journal_superblock_s
++{
++/* 0x0000 */
++      journal_header_t s_header;
++
++/* 0x000C */
++      /* Static information describing the journal */
++      __u32   s_blocksize;            /* journal device blocksize */
++      __u32   s_maxlen;               /* total blocks in journal file */
++      __u32   s_first;                /* first block of log information */
++      
++/* 0x0018 */
++      /* Dynamic information describing the current state of the log */
++      __u32   s_sequence;             /* first commit ID expected in log */
++      __u32   s_start;                /* blocknr of start of log */
++
++/* 0x0020 */
++      /* Error value, as set by journal_abort(). */
++      __s32   s_errno;
++
++/* 0x0024 */
++      /* Remaining fields are only valid in a version-2 superblock */
++      __u32   s_feature_compat;       /* compatible feature set */
++      __u32   s_feature_incompat;     /* incompatible feature set */
++      __u32   s_feature_ro_compat;    /* readonly-compatible feature set */
++/* 0x0030 */
++      __u8    s_uuid[16];             /* 128-bit uuid for journal */
++
++/* 0x0040 */
++      __u32   s_nr_users;             /* Nr of filesystems sharing log */
++      
++      __u32   s_dynsuper;             /* Blocknr of dynamic superblock copy*/
++      
++/* 0x0048 */
++      __u32   s_max_transaction;      /* Limit of journal blocks per trans.*/
++      __u32   s_max_trans_data;       /* Limit of data blocks per trans. */
++
++/* 0x0050 */
++      __u32   s_padding[44];
++
++/* 0x0100 */
++      __u8    s_users[16*48];         /* ids of all fs'es sharing the log */
++/* 0x0400 */
++} journal_superblock_t;
++
++#define JFS_HAS_COMPAT_FEATURE(j,mask)                                        \
++      ((j)->j_format_version >= 2 &&                                  \
++       ((j)->j_superblock->s_feature_compat & cpu_to_be32((mask))))
++#define JFS_HAS_RO_COMPAT_FEATURE(j,mask)                             \
++      ((j)->j_format_version >= 2 &&                                  \
++       ((j)->j_superblock->s_feature_ro_compat & cpu_to_be32((mask))))
++#define JFS_HAS_INCOMPAT_FEATURE(j,mask)                              \
++      ((j)->j_format_version >= 2 &&                                  \
++       ((j)->j_superblock->s_feature_incompat & cpu_to_be32((mask))))
++
++#define JFS_FEATURE_INCOMPAT_REVOKE   0x00000001
++
++/* Features known to this kernel version: */
++#define JFS_KNOWN_COMPAT_FEATURES     0
++#define JFS_KNOWN_ROCOMPAT_FEATURES   0
++#define JFS_KNOWN_INCOMPAT_FEATURES   JFS_FEATURE_INCOMPAT_REVOKE
++
++#ifdef __KERNEL__
++
++#include <linux/fs.h>
++#include <linux/sched.h>
++
++#define JBD_ASSERTIONS
++#ifdef JBD_ASSERTIONS
++#define J_ASSERT(assert)                                              \
++do {                                                                  \
++      if (!(assert)) {                                                \
++              printk (KERN_EMERG                                      \
++                      "Assertion failure in %s() at %s:%d: \"%s\"\n", \
++                      __FUNCTION__, __FILE__, __LINE__, # assert);    \
++              BUG();                                                  \
++      }                                                               \
++} while (0)
++
++#if defined(CONFIG_BUFFER_DEBUG)
++void buffer_assertion_failure(struct buffer_head *bh);
++#define J_ASSERT_BH(bh, expr)                                         \
++      do {                                                            \
++              if (!(expr))                                            \
++                      buffer_assertion_failure(bh);                   \
++              J_ASSERT(expr);                                         \
++      } while (0)
++#define J_ASSERT_JH(jh, expr) J_ASSERT_BH(jh2bh(jh), expr)
++#else
++#define J_ASSERT_BH(bh, expr) J_ASSERT(expr)
++#define J_ASSERT_JH(jh, expr) J_ASSERT(expr)
++#endif
++
++#else
++#define J_ASSERT(assert)
++#endif                /* JBD_ASSERTIONS */
++
++enum jbd_state_bits {
++      BH_JWrite
++        = BH_PrivateStart,    /* 1 if being written to log (@@@ DEBUGGING) */
++      BH_Freed,               /* 1 if buffer has been freed (truncated) */
++      BH_Revoked,             /* 1 if buffer has been revoked from the log */
++      BH_RevokeValid,         /* 1 if buffer revoked flag is valid */
++      BH_JBDDirty,            /* 1 if buffer is dirty but journaled */
++};
++
++/* Return true if the buffer is one which JBD is managing */
++static inline int buffer_jbd(struct buffer_head *bh)
++{
++      return __buffer_state(bh, JBD);
++}
++
++static inline struct buffer_head *jh2bh(struct journal_head *jh)
++{
++      return jh->b_bh;
++}
++
++static inline struct journal_head *bh2jh(struct buffer_head *bh)
++{
++      return bh->b_private;
++}
++
++struct jbd_revoke_table_s;
++
++/* The handle_t type represents a single atomic update being performed
++ * by some process.  All filesystem modifications made by the process go
++ * through this handle.  Recursive operations (such as quota operations)
++ * are gathered into a single update.
++ *
++ * The buffer credits field is used to account for journaled buffers
++ * being modified by the running process.  To ensure that there is
++ * enough log space for all outstanding operations, we need to limit the
++ * number of outstanding buffers possible at any time.  When the
++ * operation completes, any buffer credits not used are credited back to
++ * the transaction, so that at all times we know how many buffers the
++ * outstanding updates on a transaction might possibly touch. */
++
++struct handle_s 
++{
++      /* Which compound transaction is this update a part of? */
++      transaction_t         * h_transaction;
++
++      /* Number of remaining buffers we are allowed to dirty: */
++      int                     h_buffer_credits;
++
++      /* Reference count on this handle */
++      int                     h_ref;
++
++      /* Field for caller's use to track errors through large fs
++         operations */
++      int                     h_err;
++
++      /* Flags */
++      unsigned int    h_sync:         1;      /* sync-on-close */
++      unsigned int    h_jdata:        1;      /* force data journaling */
++      unsigned int    h_aborted:      1;      /* fatal error on handle */
++};
++
++
++/* The transaction_t type is the guts of the journaling mechanism.  It
++ * tracks a compound transaction through its various states:
++ *
++ * RUNNING:   accepting new updates
++ * LOCKED:    Updates still running but we don't accept new ones
++ * RUNDOWN:   Updates are tidying up but have finished requesting
++ *            new buffers to modify (state not used for now)
++ * FLUSH:       All updates complete, but we are still writing to disk
++ * COMMIT:      All data on disk, writing commit record
++ * FINISHED:  We still have to keep the transaction for checkpointing.
++ *
++ * The transaction keeps track of all of the buffers modified by a
++ * running transaction, and all of the buffers committed but not yet
++ * flushed to home for finished transactions.
++ */
++
++struct transaction_s 
++{
++      /* Pointer to the journal for this transaction. */
++      journal_t *             t_journal;
++      
++      /* Sequence number for this transaction */
++      tid_t                   t_tid;
++      
++      /* Transaction's current state */
++      enum {
++              T_RUNNING,
++              T_LOCKED,
++              T_RUNDOWN,
++              T_FLUSH,
++              T_COMMIT,
++              T_FINISHED 
++      }                       t_state;
++
++      /* Where in the log does this transaction's commit start? */
++      unsigned long           t_log_start;
++      
++      /* Doubly-linked circular list of all inodes owned by this
++           transaction */     /* AKPM: unused */
++      struct inode *          t_ilist;
++      
++      /* Number of buffers on the t_buffers list */
++      int                     t_nr_buffers;
++      
++      /* Doubly-linked circular list of all buffers reserved but not
++           yet modified by this transaction */
++      struct journal_head *   t_reserved_list;
++      
++      /* Doubly-linked circular list of all metadata buffers owned by this
++           transaction */
++      struct journal_head *   t_buffers;
++      
++      /*
++       * Doubly-linked circular list of all data buffers still to be
++       * flushed before this transaction can be committed.
++       * Protected by journal_datalist_lock.
++       */
++      struct journal_head *   t_sync_datalist;
++      
++      /*
++       * Doubly-linked circular list of all writepage data buffers
++       * still to be written before this transaction can be committed.
++       * Protected by journal_datalist_lock.
++       */
++      struct journal_head *   t_async_datalist;
++      
++      /* Doubly-linked circular list of all forget buffers (superceded
++           buffers which we can un-checkpoint once this transaction
++           commits) */
++      struct journal_head *   t_forget;
++      
++      /*
++       * Doubly-linked circular list of all buffers still to be
++       * flushed before this transaction can be checkpointed.
++       */
++      /* Protected by journal_datalist_lock */
++      struct journal_head *   t_checkpoint_list;
++      
++      /* Doubly-linked circular list of temporary buffers currently
++           undergoing IO in the log */
++      struct journal_head *   t_iobuf_list;
++      
++      /* Doubly-linked circular list of metadata buffers being
++           shadowed by log IO.  The IO buffers on the iobuf list and the
++           shadow buffers on this list match each other one for one at
++           all times. */
++      struct journal_head *   t_shadow_list;
++      
++      /* Doubly-linked circular list of control buffers being written
++           to the log. */
++      struct journal_head *   t_log_list;
++      
++      /* Number of outstanding updates running on this transaction */
++      int                     t_updates;
++
++      /* Number of buffers reserved for use by all handles in this
++       * transaction handle but not yet modified. */
++      int                     t_outstanding_credits;
++      
++      /*
++       * Forward and backward links for the circular list of all
++       * transactions awaiting checkpoint.
++       */
++      /* Protected by journal_datalist_lock */
++      transaction_t           *t_cpnext, *t_cpprev;
++
++      /* When will the transaction expire (become due for commit), in
++       * jiffies ? */
++      unsigned long           t_expires;
++
++      /* How many handles used this transaction? */
++      int t_handle_count;
++};
++
++
++/* The journal_t maintains all of the journaling state information for a
++ * single filesystem.  It is linked to from the fs superblock structure.
++ * 
++ * We use the journal_t to keep track of all outstanding transaction
++ * activity on the filesystem, and to manage the state of the log
++ * writing process. */
++
++struct journal_s
++{
++      /* General journaling state flags */
++      unsigned long           j_flags;
++
++      /* Is there an outstanding uncleared error on the journal (from
++       * a prior abort)? */
++      int                     j_errno;
++      
++      /* The superblock buffer */
++      struct buffer_head *    j_sb_buffer;
++      journal_superblock_t *  j_superblock;
++
++      /* Version of the superblock format */
++      int                     j_format_version;
++
++      /* Number of processes waiting to create a barrier lock */
++      int                     j_barrier_count;
++      
++      /* The barrier lock itself */
++      struct semaphore        j_barrier;
++      
++      /* Transactions: The current running transaction... */
++      transaction_t *         j_running_transaction;
++      
++      /* ... the transaction we are pushing to disk ... */
++      transaction_t *         j_committing_transaction;
++      
++      /* ... and a linked circular list of all transactions waiting
++       * for checkpointing. */
++      /* Protected by journal_datalist_lock */
++      transaction_t *         j_checkpoint_transactions;
++
++      /* Wait queue for waiting for a locked transaction to start
++           committing, or for a barrier lock to be released */
++      wait_queue_head_t       j_wait_transaction_locked;
++      
++      /* Wait queue for waiting for checkpointing to complete */
++      wait_queue_head_t       j_wait_logspace;
++      
++      /* Wait queue for waiting for commit to complete */
++      wait_queue_head_t       j_wait_done_commit;
++      
++      /* Wait queue to trigger checkpointing */
++      wait_queue_head_t       j_wait_checkpoint;
++      
++      /* Wait queue to trigger commit */
++      wait_queue_head_t       j_wait_commit;
++      
++      /* Wait queue to wait for updates to complete */
++      wait_queue_head_t       j_wait_updates;
++
++      /* Semaphore for locking against concurrent checkpoints */
++      struct semaphore        j_checkpoint_sem;
++
++      /* The main journal lock, used by lock_journal() */
++      struct semaphore        j_sem;
++              
++      /* Journal head: identifies the first unused block in the journal. */
++      unsigned long           j_head;
++      
++      /* Journal tail: identifies the oldest still-used block in the
++       * journal. */
++      unsigned long           j_tail;
++
++      /* Journal free: how many free blocks are there in the journal? */
++      unsigned long           j_free;
++
++      /* Journal start and end: the block numbers of the first usable
++       * block and one beyond the last usable block in the journal. */
++      unsigned long           j_first, j_last;
++
++      /* Device, blocksize and starting block offset for the location
++       * where we store the journal. */
++      kdev_t                  j_dev;
++      int                     j_blocksize;
++      unsigned int            j_blk_offset;
++
++      /* Device which holds the client fs.  For internal journal this
++       * will be equal to j_dev. */
++      kdev_t                  j_fs_dev;
++
++      /* Total maximum capacity of the journal region on disk. */
++      unsigned int            j_maxlen;
++
++      /* Optional inode where we store the journal.  If present, all
++       * journal block numbers are mapped into this inode via
++       * bmap(). */
++      struct inode *          j_inode;
++
++      /* Sequence number of the oldest transaction in the log */
++      tid_t                   j_tail_sequence;
++      /* Sequence number of the next transaction to grant */
++      tid_t                   j_transaction_sequence;
++      /* Sequence number of the most recently committed transaction */
++      tid_t                   j_commit_sequence;
++      /* Sequence number of the most recent transaction wanting commit */
++      tid_t                   j_commit_request;
++
++      /* Journal uuid: identifies the object (filesystem, LVM volume
++       * etc) backed by this journal.  This will eventually be
++       * replaced by an array of uuids, allowing us to index multiple
++       * devices within a single journal and to perform atomic updates
++       * across them.  */
++
++      __u8                    j_uuid[16];
++
++      /* Pointer to the current commit thread for this journal */
++      struct task_struct *    j_task;
++
++      /* Maximum number of metadata buffers to allow in a single
++       * compound commit transaction */
++      int                     j_max_transaction_buffers;
++
++      /* What is the maximum transaction lifetime before we begin a
++       * commit? */
++      unsigned long           j_commit_interval;
++
++      /* The timer used to wakeup the commit thread: */
++      struct timer_list *     j_commit_timer;
++      int                     j_commit_timer_active;
++
++      /* Link all journals together - system-wide */
++      struct list_head        j_all_journals;
++
++      /* The revoke table: maintains the list of revoked blocks in the
++           current transaction. */
++      struct jbd_revoke_table_s *j_revoke;
++};
++
++/* 
++ * Journal flag definitions 
++ */
++#define JFS_UNMOUNT   0x001   /* Journal thread is being destroyed */
++#define JFS_ABORT     0x002   /* Journaling has been aborted for errors. */
++#define JFS_ACK_ERR   0x004   /* The errno in the sb has been acked */
++#define JFS_FLUSHED   0x008   /* The journal superblock has been flushed */
++#define JFS_LOADED    0x010   /* The journal superblock has been loaded */
++
++/* 
++ * Function declarations for the journaling transaction and buffer
++ * management
++ */
++
++/* Filing buffers */
++extern void __journal_unfile_buffer(struct journal_head *);
++extern void journal_unfile_buffer(struct journal_head *);
++extern void __journal_refile_buffer(struct journal_head *);
++extern void journal_refile_buffer(struct journal_head *);
++extern void __journal_file_buffer(struct journal_head *, transaction_t *, int);
++extern void __journal_free_buffer(struct journal_head *bh);
++extern void journal_file_buffer(struct journal_head *, transaction_t *, int);
++extern void __journal_clean_data_list(transaction_t *transaction);
++
++/* Log buffer allocation */
++extern struct journal_head * journal_get_descriptor_buffer(journal_t *);
++extern unsigned long journal_next_log_block(journal_t *);
++
++/* Commit management */
++extern void journal_commit_transaction(journal_t *);
++
++/* Checkpoint list management */
++int __journal_clean_checkpoint_list(journal_t *journal);
++extern void journal_remove_checkpoint(struct journal_head *);
++extern void __journal_remove_checkpoint(struct journal_head *);
++extern void journal_insert_checkpoint(struct journal_head *, transaction_t *);
++extern void __journal_insert_checkpoint(struct journal_head *,transaction_t *);
++
++/* Buffer IO */
++extern int 
++journal_write_metadata_buffer(transaction_t     *transaction,
++                            struct journal_head  *jh_in,
++                            struct journal_head **jh_out,
++                            int                  blocknr);
++
++/* Transaction locking */
++extern void           __wait_on_journal (journal_t *);
++
++/*
++ * Journal locking.
++ *
++ * We need to lock the journal during transaction state changes so that
++ * nobody ever tries to take a handle on the running transaction while
++ * we are in the middle of moving it to the commit phase.  
++ *
++ * Note that the locking is completely interrupt unsafe.  We never touch
++ * journal structures from interrupts.
++ *
++ * In 2.2, the BKL was required for lock_journal.  This is no longer
++ * the case.
++ */
++
++static inline void lock_journal(journal_t *journal)
++{
++      down(&journal->j_sem);
++}
++
++/* This returns zero if we acquired the semaphore */
++static inline int try_lock_journal(journal_t * journal)
++{
++      return down_trylock(&journal->j_sem);
++}
++
++static inline void unlock_journal(journal_t * journal)
++{
++      up(&journal->j_sem);
++}
++
++
++static inline handle_t *journal_current_handle(void)
++{
++      return current->journal_info;
++}
++
++/* The journaling code user interface:
++ *
++ * Create and destroy handles
++ * Register buffer modifications against the current transaction. 
++ */
++
++extern handle_t *journal_start(journal_t *, int nblocks);
++extern handle_t *journal_try_start(journal_t *, int nblocks);
++extern int     journal_restart (handle_t *, int nblocks);
++extern int     journal_extend (handle_t *, int nblocks);
++extern int     journal_get_write_access (handle_t *, struct buffer_head *);
++extern int     journal_get_create_access (handle_t *, struct buffer_head *);
++extern int     journal_get_undo_access (handle_t *, struct buffer_head *);
++extern int     journal_dirty_data (handle_t *,
++                              struct buffer_head *, int async);
++extern int     journal_dirty_metadata (handle_t *, struct buffer_head *);
++extern void    journal_release_buffer (handle_t *, struct buffer_head *);
++extern void    journal_forget (handle_t *, struct buffer_head *);
++extern void    journal_sync_buffer (struct buffer_head *);
++extern int     journal_flushpage(journal_t *, struct page *, unsigned long);
++extern int     journal_try_to_free_buffers(journal_t *, struct page *, int);
++extern int     journal_stop(handle_t *);
++extern int     journal_flush (journal_t *);
++
++extern void    journal_lock_updates (journal_t *);
++extern void    journal_unlock_updates (journal_t *);
++
++extern journal_t * journal_init_dev(kdev_t dev, kdev_t fs_dev,
++                              int start, int len, int bsize);
++extern journal_t * journal_init_inode (struct inode *);
++extern int       journal_update_format (journal_t *);
++extern int       journal_check_used_features 
++                 (journal_t *, unsigned long, unsigned long, unsigned long);
++extern int       journal_check_available_features 
++                 (journal_t *, unsigned long, unsigned long, unsigned long);
++extern int       journal_set_features 
++                 (journal_t *, unsigned long, unsigned long, unsigned long);
++extern int       journal_create     (journal_t *);
++extern int       journal_load       (journal_t *journal);
++extern void      journal_destroy    (journal_t *);
++extern int       journal_recover    (journal_t *journal);
++extern int       journal_wipe       (journal_t *, int);
++extern int       journal_skip_recovery (journal_t *);
++extern void      journal_update_superblock (journal_t *, int);
++extern void      __journal_abort      (journal_t *);
++extern void      journal_abort      (journal_t *, int);
++extern int       journal_errno      (journal_t *);
++extern void      journal_ack_err    (journal_t *);
++extern int       journal_clear_err  (journal_t *);
++extern unsigned long journal_bmap(journal_t *journal, unsigned long blocknr);
++extern int        journal_force_commit(journal_t *journal);
++
++/*
++ * journal_head management
++ */
++extern struct journal_head
++              *journal_add_journal_head(struct buffer_head *bh);
++extern void   journal_remove_journal_head(struct buffer_head *bh);
++extern void   __journal_remove_journal_head(struct buffer_head *bh);
++extern void   journal_unlock_journal_head(struct journal_head *jh);
++
++/* Primary revoke support */
++#define JOURNAL_REVOKE_DEFAULT_HASH 256
++extern int       journal_init_revoke(journal_t *, int);
++extern void      journal_destroy_revoke_caches(void);
++extern int       journal_init_revoke_caches(void);
++
++extern void      journal_destroy_revoke(journal_t *);
++extern int       journal_revoke (handle_t *,
++                              unsigned long, struct buffer_head *);
++extern int       journal_cancel_revoke(handle_t *, struct journal_head *);
++extern void      journal_write_revoke_records(journal_t *, transaction_t *);
++
++/* Recovery revoke support */
++extern int       journal_set_revoke(journal_t *, unsigned long, tid_t);
++extern int       journal_test_revoke(journal_t *, unsigned long, tid_t);
++extern void      journal_clear_revoke(journal_t *);
++extern void      journal_brelse_array(struct buffer_head *b[], int n);
++
++/* The log thread user interface:
++ *
++ * Request space in the current transaction, and force transaction commit
++ * transitions on demand.
++ */
++
++extern int    log_space_left (journal_t *); /* Called with journal locked */
++extern tid_t  log_start_commit (journal_t *, transaction_t *);
++extern void   log_wait_commit (journal_t *, tid_t);
++extern int    log_do_checkpoint (journal_t *, int);
++
++extern void   log_wait_for_space(journal_t *, int nblocks);
++extern void   __journal_drop_transaction(journal_t *, transaction_t *);
++extern int    cleanup_journal_tail(journal_t *);
++
++/* Reduce journal memory usage by flushing */
++extern void shrink_journal_memory(void);
++
++/* Debugging code only: */
++
++#define jbd_ENOSYS() \
++do {                                                                \
++      printk (KERN_ERR "JBD unimplemented function " __FUNCTION__); \
++      current->state = TASK_UNINTERRUPTIBLE;                        \
++      schedule();                                                   \
++} while (1)
++
++/*
++ * is_journal_abort
++ *
++ * Simple test wrapper function to test the JFS_ABORT state flag.  This
++ * bit, when set, indicates that we have had a fatal error somewhere,
++ * either inside the journaling layer or indicated to us by the client
++ * (eg. ext3), and that we and should not commit any further
++ * transactions.  
++ */
++
++static inline int is_journal_aborted(journal_t *journal)
++{
++      return journal->j_flags & JFS_ABORT;
++}
++
++static inline int is_handle_aborted(handle_t *handle)
++{
++      if (handle->h_aborted)
++              return 1;
++      return is_journal_aborted(handle->h_transaction->t_journal);
++}
++
++static inline void journal_abort_handle(handle_t *handle)
++{
++      handle->h_aborted = 1;
++}
++
++/* Not all architectures define BUG() */
++#ifndef BUG
++#define BUG() do { \
++        printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
++      * ((char *) 0) = 0; \
++ } while (0)
++#endif /* BUG */
++
++#else
++
++extern int       journal_recover    (journal_t *journal);
++extern int       journal_skip_recovery (journal_t *);
++
++/* Primary revoke support */
++extern int       journal_init_revoke(journal_t *, int);
++extern void      journal_destroy_revoke_caches(void);
++extern int       journal_init_revoke_caches(void);
++
++/* Recovery revoke support */
++extern int       journal_set_revoke(journal_t *, unsigned long, tid_t);
++extern int       journal_test_revoke(journal_t *, unsigned long, tid_t);
++extern void      journal_clear_revoke(journal_t *);
++extern void      journal_brelse_array(struct buffer_head *b[], int n);
++
++extern void      journal_destroy_revoke(journal_t *);
++#endif /* __KERNEL__   */
++
++/* Comparison functions for transaction IDs: perform comparisons using
++ * modulo arithmetic so that they work over sequence number wraps. */
++
++static inline int tid_gt(tid_t x, tid_t y)
++{
++      int difference = (x - y);
++      return (difference > 0);
++}
++
++static inline int tid_geq(tid_t x, tid_t y)
++{
++      int difference = (x - y);
++      return (difference >= 0);
++}
++
++extern int journal_blocks_per_page(struct inode *inode);
++
++/*
++ * Definitions which augment the buffer_head layer
++ */
++
++/* journaling buffer types */
++#define BJ_None               0       /* Not journaled */
++#define BJ_SyncData   1       /* Normal data: flush before commit */
++#define BJ_AsyncData  2       /* writepage data: wait on it before commit */
++#define BJ_Metadata   3       /* Normal journaled metadata */
++#define BJ_Forget     4       /* Buffer superceded by this transaction */
++#define BJ_IO         5       /* Buffer is for temporary IO use */
++#define BJ_Shadow     6       /* Buffer contents being shadowed to the log */
++#define BJ_LogCtl     7       /* Buffer contains log descriptors */
++#define BJ_Reserved   8       /* Buffer is reserved for access by journal */
++#define BJ_Types      9
++ 
++extern int jbd_blocks_per_page(struct inode *inode);
++
++#ifdef __KERNEL__
++
++extern spinlock_t jh_splice_lock;
++/*
++ * Once `expr1' has been found true, take jh_splice_lock
++ * and then reevaluate everything.
++ */
++#define SPLICE_LOCK(expr1, expr2)                             \
++      ({                                                      \
++              int ret = (expr1);                              \
++              if (ret) {                                      \
++                      spin_lock(&jh_splice_lock);             \
++                      ret = (expr1) && (expr2);               \
++                      spin_unlock(&jh_splice_lock);           \
++              }                                               \
++              ret;                                            \
++      })
++
++/*
++ * A number of buffer state predicates.  They test for
++ * buffer_jbd() because they are used in core kernel code.
++ *
++ * These will be racy on SMP unless we're *sure* that the
++ * buffer won't be detached from the journalling system
++ * in parallel.
++ */
++
++/* Return true if the buffer is on journal list `list' */
++static inline int buffer_jlist_eq(struct buffer_head *bh, int list)
++{
++      return SPLICE_LOCK(buffer_jbd(bh), bh2jh(bh)->b_jlist == list);
++}
++
++/* Return true if this bufer is dirty wrt the journal */
++static inline int buffer_jdirty(struct buffer_head *bh)
++{
++      return buffer_jbd(bh) && __buffer_state(bh, JBDDirty);
++}
++
++/* Return true if it's a data buffer which journalling is managing */
++static inline int buffer_jbd_data(struct buffer_head *bh)
++{
++      return SPLICE_LOCK(buffer_jbd(bh),
++                      bh2jh(bh)->b_jlist == BJ_SyncData ||
++                      bh2jh(bh)->b_jlist == BJ_AsyncData);
++}
++
++#ifdef CONFIG_SMP
++#define assert_spin_locked(lock)      J_ASSERT(spin_is_locked(lock))
++#else
++#define assert_spin_locked(lock)      do {} while(0)
++#endif
++
++#define buffer_trace_init(bh) do {} while (0)
++#define print_buffer_fields(bh)       do {} while (0)
++#define print_buffer_trace(bh)        do {} while (0)
++#define BUFFER_TRACE(bh, info)        do {} while (0)
++#define BUFFER_TRACE2(bh, bh2, info)  do {} while (0)
++#define JBUFFER_TRACE(jh, info)       do {} while (0)
++
++#endif        /* __KERNEL__ */
++
++#endif        /* CONFIG_JBD || CONFIG_JBD_MODULE || !__KERNEL__ */
++
++/*
++ * Compatibility no-ops which allow the kernel to compile without CONFIG_JBD
++ * go here.
++ */
++
++#if defined(__KERNEL__) && !(defined(CONFIG_JBD) || defined(CONFIG_JBD_MODULE))
++
++#define J_ASSERT(expr)                        do {} while (0)
++#define J_ASSERT_BH(bh, expr)         do {} while (0)
++#define buffer_jbd(bh)                        0
++#define buffer_jlist_eq(bh, val)      0
++#define journal_buffer_journal_lru(bh)        0
++
++#endif        /* defined(__KERNEL__) && !defined(CONFIG_JBD) */
++#endif        /* _LINUX_JBD_H */
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/kernel-list.h busybox/e2fsprogs/ext2fs/kernel-list.h
+--- busybox-1.00/e2fsprogs/ext2fs/kernel-list.h        1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/kernel-list.h     2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,112 @@
++#ifndef _LINUX_LIST_H
++#define _LINUX_LIST_H
++
++/*
++ * Simple doubly linked list implementation.
++ *
++ * Some of the internal functions ("__xxx") are useful when
++ * manipulating whole lists rather than single entries, as
++ * sometimes we already know the next/prev entries and we can
++ * generate better code by using them directly rather than
++ * using the generic single-entry routines.
++ */
++
++struct list_head {
++      struct list_head *next, *prev;
++};
++
++#define LIST_HEAD_INIT(name) { &(name), &(name) }
++
++#define LIST_HEAD(name) \
++      struct list_head name = { &name, &name }
++
++#define INIT_LIST_HEAD(ptr) do { \
++      (ptr)->next = (ptr); (ptr)->prev = (ptr); \
++} while (0)
++
++#if (!defined(__GNUC__) && !defined(__WATCOMC__))
++#define __inline__
++#endif
++
++/*
++ * Insert a new entry between two known consecutive entries. 
++ *
++ * This is only for internal list manipulation where we know
++ * the prev/next entries already!
++ */
++static __inline__ void __list_add(struct list_head * new,
++      struct list_head * prev,
++      struct list_head * next)
++{
++      next->prev = new;
++      new->next = next;
++      new->prev = prev;
++      prev->next = new;
++}
++
++/*
++ * Insert a new entry after the specified head..
++ */
++static __inline__ void list_add(struct list_head *new, struct list_head *head)
++{
++      __list_add(new, head, head->next);
++}
++
++/*
++ * Insert a new entry at the tail
++ */
++static __inline__ void list_add_tail(struct list_head *new, struct list_head *head)
++{
++      __list_add(new, head->prev, head);
++}
++
++/*
++ * Delete a list entry by making the prev/next entries
++ * point to each other.
++ *
++ * This is only for internal list manipulation where we know
++ * the prev/next entries already!
++ */
++static __inline__ void __list_del(struct list_head * prev,
++                                struct list_head * next)
++{
++      next->prev = prev;
++      prev->next = next;
++}
++
++static __inline__ void list_del(struct list_head *entry)
++{
++      __list_del(entry->prev, entry->next);
++}
++
++static __inline__ int list_empty(struct list_head *head)
++{
++      return head->next == head;
++}
++
++/*
++ * Splice in "list" into "head"
++ */
++static __inline__ void list_splice(struct list_head *list, struct list_head *head)
++{
++      struct list_head *first = list->next;
++
++      if (first != list) {
++              struct list_head *last = list->prev;
++              struct list_head *at = head->next;
++
++              first->prev = head;
++              head->next = first;
++
++              last->next = at;
++              at->prev = last;
++      }
++}
++
++#define list_entry(ptr, type, member) \
++      ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
++
++#define list_for_each(pos, head) \
++        for (pos = (head)->next; pos != (head); pos = pos->next)
++
++#endif
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/link.c busybox/e2fsprogs/ext2fs/link.c
+--- busybox-1.00/e2fsprogs/ext2fs/link.c       1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/link.c    2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,134 @@
++/*
++ * link.c --- create links in a ext2fs directory
++ * 
++ * Copyright (C) 1993, 1994 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++struct link_struct  {
++      const char      *name;
++      int             namelen;
++      ext2_ino_t      inode;
++      int             flags;
++      int             done;
++      struct ext2_super_block *sb;
++};    
++
++static int link_proc(struct ext2_dir_entry *dirent,
++                   int        offset,
++                   int        blocksize,
++                   char       *buf,
++                   void       *priv_data)
++{
++      struct link_struct *ls = (struct link_struct *) priv_data;
++      struct ext2_dir_entry *next;
++      int rec_len, min_rec_len;
++      int ret = 0;
++
++      rec_len = EXT2_DIR_REC_LEN(ls->namelen);
++
++      /*
++       * See if the following directory entry (if any) is unused;
++       * if so, absorb it into this one.
++       */
++      next = (struct ext2_dir_entry *) (buf + offset + dirent->rec_len);
++      if ((offset + dirent->rec_len < blocksize - 8) &&
++          (next->inode == 0) &&
++          (offset + dirent->rec_len + next->rec_len <= blocksize)) {
++              dirent->rec_len += next->rec_len;
++              ret = DIRENT_CHANGED;
++      }
++
++      /*
++       * If the directory entry is used, see if we can split the
++       * directory entry to make room for the new name.  If so,
++       * truncate it and return.
++       */
++      if (dirent->inode) {
++              min_rec_len = EXT2_DIR_REC_LEN(dirent->name_len & 0xFF);
++              if (dirent->rec_len < (min_rec_len + rec_len))
++                      return ret;
++              rec_len = dirent->rec_len - min_rec_len;
++              dirent->rec_len = min_rec_len;
++              next = (struct ext2_dir_entry *) (buf + offset +
++                                                dirent->rec_len);
++              next->inode = 0;
++              next->name_len = 0;
++              next->rec_len = rec_len;
++              return DIRENT_CHANGED;
++      }
++
++      /*
++       * If we get this far, then the directory entry is not used.
++       * See if we can fit the request entry in.  If so, do it.
++       */
++      if (dirent->rec_len < rec_len)
++              return ret;
++      dirent->inode = ls->inode;
++      dirent->name_len = ls->namelen;
++      strncpy(dirent->name, ls->name, ls->namelen);
++      if (ls->sb->s_feature_incompat & EXT2_FEATURE_INCOMPAT_FILETYPE)
++              dirent->name_len |= (ls->flags & 0x7) << 8;
++
++      ls->done++;
++      return DIRENT_ABORT|DIRENT_CHANGED;
++}
++
++/*
++ * Note: the low 3 bits of the flags field are used as the directory
++ * entry filetype.
++ */
++#ifdef __TURBOC__
++ #pragma argsused
++#endif
++errcode_t ext2fs_link(ext2_filsys fs, ext2_ino_t dir, const char *name, 
++                    ext2_ino_t ino, int flags)
++{
++      errcode_t               retval;
++      struct link_struct      ls;
++      struct ext2_inode       inode;
++
++      EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
++
++      if (!(fs->flags & EXT2_FLAG_RW))
++              return EXT2_ET_RO_FILSYS;
++
++      ls.name = name;
++      ls.namelen = name ? strlen(name) : 0;
++      ls.inode = ino;
++      ls.flags = flags;
++      ls.done = 0;
++      ls.sb = fs->super;
++
++      retval = ext2fs_dir_iterate(fs, dir, DIRENT_FLAG_INCLUDE_EMPTY,
++                                  0, link_proc, &ls);
++      if (retval)
++              return retval;
++
++      if (!ls.done)
++              return EXT2_ET_DIR_NO_SPACE;
++
++      if ((retval = ext2fs_read_inode(fs, dir, &inode)) != 0)
++              return retval;
++
++      if (inode.i_flags & EXT2_INDEX_FL) {
++              inode.i_flags &= ~EXT2_INDEX_FL;
++              if ((retval = ext2fs_write_inode(fs, dir, &inode)) != 0)
++                      return retval;
++      }
++
++      return 0;
++}
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/llseek.c busybox/e2fsprogs/ext2fs/llseek.c
+--- busybox-1.00/e2fsprogs/ext2fs/llseek.c     1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/llseek.c  2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,135 @@
++/*
++ * llseek.c -- stub calling the llseek system call
++ *
++ * Copyright (C) 1994, 1995, 1996, 1997 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#if HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++
++#if HAVE_ERRNO_H
++#include <errno.h>
++#endif
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#ifdef __MSDOS__
++#include <io.h>
++#endif
++#include "et/com_err.h"
++#include "ext2fs/ext2_io.h"
++
++#ifdef __linux__
++
++#if defined(HAVE_LSEEK64) && defined(HAVE_LSEEK64_PROTOTYPE)
++
++#define my_llseek lseek64
++
++#else
++#if defined(HAVE_LLSEEK)
++#include <syscall.h>
++
++#ifndef HAVE_LLSEEK_PROTOTYPE
++extern long long llseek (int fd, long long offset, int origin);
++#endif
++
++#define my_llseek llseek
++
++#else /* ! HAVE_LLSEEK */
++
++#if defined(__alpha__) || defined (__ia64__)
++
++#define llseek lseek
++
++#else /* !__alpha__ && !__ia64__*/
++
++#include <linux/unistd.h>
++
++#ifndef __NR__llseek
++#define __NR__llseek            140
++#endif
++
++#ifndef __i386__
++static int _llseek (unsigned int, unsigned long,
++                 unsigned long, ext2_loff_t *, unsigned int);
++
++static _syscall5(int,_llseek,unsigned int,fd,unsigned long,offset_high,
++               unsigned long, offset_low,ext2_loff_t *,result,
++               unsigned int, origin)
++#endif
++
++static ext2_loff_t my_llseek (int fd, ext2_loff_t offset, int origin)
++{
++      ext2_loff_t result;
++      int retval;
++
++#ifndef __i386__
++      retval = _llseek(fd, ((unsigned long long) offset) >> 32,
++#else                   
++      retval = syscall(__NR__llseek, fd, (unsigned long long) (offset >> 32),
++#endif
++                        ((unsigned long long) offset) & 0xffffffff,
++                      &result, origin);
++      return (retval == -1 ? (ext2_loff_t) retval : result);
++}
++
++#endif        /* __alpha__ || __ia64__ */
++
++#endif /* HAVE_LLSEEK */
++#endif /* defined(HAVE_LSEEK64) && defined(HAVE_LSEEK64_PROTOTYPE) */
++
++ext2_loff_t ext2fs_llseek (int fd, ext2_loff_t offset, int origin)
++{
++      ext2_loff_t result;
++      static int do_compat = 0;
++
++      if ((sizeof(off_t) >= sizeof(ext2_loff_t)) ||
++          (offset < ((ext2_loff_t) 1 << ((sizeof(off_t)*8) -1))))
++              return lseek(fd, (off_t) offset, origin);
++
++      if (do_compat) {
++              errno = EINVAL;
++              return -1;
++      }
++      
++      result = my_llseek (fd, offset, origin);
++      if (result == -1 && errno == ENOSYS) {
++              /*
++               * Just in case this code runs on top of an old kernel
++               * which does not support the llseek system call
++               */
++              do_compat++;
++              errno = EINVAL;
++      }
++      return result;
++}
++
++#else /* !linux */
++
++#ifndef EINVAL
++#define EINVAL EXT2_ET_INVALID_ARGUMENT
++#endif
++
++ext2_loff_t ext2fs_llseek (int fd, ext2_loff_t offset, int origin)
++{
++#if defined(HAVE_LSEEK64) && defined(HAVE_LSEEK64_PROTOTYPE)
++      return lseek64 (fd, offset, origin);
++#else
++      if ((sizeof(off_t) < sizeof(ext2_loff_t)) &&
++          (offset >= ((ext2_loff_t) 1 << ((sizeof(off_t)*8) -1)))) {
++              errno = EINVAL;
++              return -1;
++      }
++      return lseek (fd, (off_t) offset, origin);
++#endif
++}
++
++#endif        /* linux */
++
++
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/lookup.c busybox/e2fsprogs/ext2fs/lookup.c
+--- busybox-1.00/e2fsprogs/ext2fs/lookup.c     1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/lookup.c  2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,69 @@
++/*
++ * lookup.c --- ext2fs directory lookup operations
++ * 
++ * Copyright (C) 1993, 1994, 1994, 1995 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++struct lookup_struct  {
++      const char      *name;
++      int             len;
++      ext2_ino_t      *inode;
++      int             found;
++};    
++
++#ifdef __TURBOC__
++ #pragma argsused
++#endif
++static int lookup_proc(struct ext2_dir_entry *dirent,
++                     int      offset EXT2FS_ATTR((unused)),
++                     int      blocksize EXT2FS_ATTR((unused)),
++                     char     *buf EXT2FS_ATTR((unused)),
++                     void     *priv_data)
++{
++      struct lookup_struct *ls = (struct lookup_struct *) priv_data;
++
++      if (ls->len != (dirent->name_len & 0xFF))
++              return 0;
++      if (strncmp(ls->name, dirent->name, (dirent->name_len & 0xFF)))
++              return 0;
++      *ls->inode = dirent->inode;
++      ls->found++;
++      return DIRENT_ABORT;
++}
++
++
++errcode_t ext2fs_lookup(ext2_filsys fs, ext2_ino_t dir, const char *name,
++                      int namelen, char *buf, ext2_ino_t *inode)
++{
++      errcode_t       retval;
++      struct lookup_struct ls;
++
++      EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
++
++      ls.name = name;
++      ls.len = namelen;
++      ls.inode = inode;
++      ls.found = 0;
++
++      retval = ext2fs_dir_iterate(fs, dir, 0, buf, lookup_proc, &ls);
++      if (retval)
++              return retval;
++
++      return (ls.found) ? 0 : EXT2_ET_FILE_NOT_FOUND;
++}
++
++
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/mkdir.c busybox/e2fsprogs/ext2fs/mkdir.c
+--- busybox-1.00/e2fsprogs/ext2fs/mkdir.c      1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/mkdir.c   2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,142 @@
++/*
++ * mkdir.c --- make a directory in the filesystem
++ * 
++ * Copyright (C) 1994, 1995 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <fcntl.h>
++#include <time.h>
++#if HAVE_SYS_STAT_H
++#include <sys/stat.h>
++#endif
++#if HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++#ifndef EXT2_FT_DIR
++#define EXT2_FT_DIR           2
++#endif
++
++errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
++                     const char *name)
++{
++      errcode_t               retval;
++      struct ext2_inode       parent_inode, inode;
++      ext2_ino_t              ino = inum;
++      ext2_ino_t              scratch_ino;
++      blk_t                   blk;
++      char                    *block = 0;
++
++      EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
++
++      /*
++       * Allocate an inode, if necessary
++       */
++      if (!ino) {
++              retval = ext2fs_new_inode(fs, parent, LINUX_S_IFDIR | 0755,
++                                        0, &ino);
++              if (retval)
++                      goto cleanup;
++      }
++
++      /*
++       * Allocate a data block for the directory
++       */
++      retval = ext2fs_new_block(fs, 0, 0, &blk);
++      if (retval)
++              goto cleanup;
++
++      /*
++       * Create a scratch template for the directory
++       */
++      retval = ext2fs_new_dir_block(fs, ino, parent, &block);
++      if (retval)
++              goto cleanup;
++
++      /*
++       * Get the parent's inode, if necessary
++       */
++      if (parent != ino) {
++              retval = ext2fs_read_inode(fs, parent, &parent_inode);
++              if (retval)
++                      goto cleanup;
++      } else
++              memset(&parent_inode, 0, sizeof(parent_inode));
++
++      /*
++       * Create the inode structure....
++       */
++      memset(&inode, 0, sizeof(struct ext2_inode));
++      inode.i_mode = LINUX_S_IFDIR | (0777 & ~fs->umask);
++      inode.i_uid = inode.i_gid = 0;
++      inode.i_blocks = fs->blocksize / 512;
++      inode.i_block[0] = blk;
++      inode.i_links_count = 2;
++      inode.i_ctime = inode.i_atime = inode.i_mtime = time(NULL);
++      inode.i_size = fs->blocksize;
++
++      /*
++       * Write out the inode and inode data block
++       */
++      retval = ext2fs_write_dir_block(fs, blk, block);
++      if (retval)
++              goto cleanup;
++      retval = ext2fs_write_new_inode(fs, ino, &inode); 
++      if (retval)
++              goto cleanup;
++
++      /*
++       * Link the directory into the filesystem hierarchy
++       */
++      if (name) {
++              retval = ext2fs_lookup(fs, parent, name, strlen(name), 0,
++                                     &scratch_ino);
++              if (!retval) {
++                      retval = EXT2_ET_DIR_EXISTS;
++                      name = 0;
++                      goto cleanup;
++              }
++              if (retval != EXT2_ET_FILE_NOT_FOUND)
++                      goto cleanup;
++              retval = ext2fs_link(fs, parent, name, ino, EXT2_FT_DIR);
++              if (retval)
++                      goto cleanup;
++      }
++
++      /*
++       * Update parent inode's counts
++       */
++      if (parent != ino) {
++              parent_inode.i_links_count++;
++              retval = ext2fs_write_inode(fs, parent, &parent_inode);
++              if (retval)
++                      goto cleanup;
++      }
++      
++      /*
++       * Update accounting....
++       */
++      ext2fs_block_alloc_stats(fs, blk, +1);
++      ext2fs_inode_alloc_stats2(fs, ino, +1, 1);
++
++cleanup:
++      if (block)
++              ext2fs_free_mem(&block);
++      return retval;
++
++}
++
++
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/mkjournal.c busybox/e2fsprogs/ext2fs/mkjournal.c
+--- busybox-1.00/e2fsprogs/ext2fs/mkjournal.c  1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/mkjournal.c       2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,425 @@
++/*
++ * mkjournal.c --- make a journal for a filesystem
++ *
++ * Copyright (C) 2000 Theodore Ts'o.
++ * 
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#if HAVE_ERRNO_H
++#include <errno.h>
++#endif
++#include <fcntl.h>
++#include <time.h>
++#if HAVE_SYS_STAT_H
++#include <sys/stat.h>
++#endif
++#if HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++#if HAVE_SYS_IOCTL_H
++#include <sys/ioctl.h>
++#endif
++#if HAVE_NETINET_IN_H
++#include <netinet/in.h>
++#endif
++
++#include "ext2_fs.h"
++#include "e2p/e2p.h"
++#include "ext2fs.h"
++#include "jfs_user.h"
++
++/*
++ * This function automatically sets up the journal superblock and
++ * returns it as an allocated block.
++ */
++errcode_t ext2fs_create_journal_superblock(ext2_filsys fs,
++                                         __u32 size, int flags,
++                                         char  **ret_jsb)
++{
++      errcode_t               retval;
++      journal_superblock_t    *jsb;
++
++      if (size < 1024)
++              return EXT2_ET_JOURNAL_TOO_SMALL;
++
++      if ((retval = ext2fs_get_mem(fs->blocksize, &jsb)))
++              return retval;
++
++      memset (jsb, 0, fs->blocksize);
++
++      jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER);
++      if (flags & EXT2_MKJOURNAL_V1_SUPER)
++              jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V1);
++      else
++              jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2);
++      jsb->s_blocksize = htonl(fs->blocksize);
++      jsb->s_maxlen = htonl(size);
++      jsb->s_nr_users = htonl(1);
++      jsb->s_first = htonl(1);
++      jsb->s_sequence = htonl(1);
++      memcpy(jsb->s_uuid, fs->super->s_uuid, sizeof(fs->super->s_uuid));
++      /*
++       * If we're creating an external journal device, we need to
++       * adjust these fields.
++       */
++      if (fs->super->s_feature_incompat &
++          EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
++              jsb->s_nr_users = 0;
++              if (fs->blocksize == 1024)
++                      jsb->s_first = htonl(3);
++              else
++                      jsb->s_first = htonl(2);
++      }
++
++      *ret_jsb = (char *) jsb;
++      return 0;
++}
++
++/*
++ * This function writes a journal using POSIX routines.  It is used
++ * for creating external journals and creating journals on live
++ * filesystems.
++ */
++static errcode_t write_journal_file(ext2_filsys fs, char *filename,
++                                  blk_t size, int flags)
++{
++      errcode_t       retval;
++      char            *buf = 0;
++      int             fd, ret_size;
++      blk_t           i;
++
++      if ((retval = ext2fs_create_journal_superblock(fs, size, flags, &buf)))
++              return retval;
++
++      /* Open the device or journal file */
++      if ((fd = open(filename, O_WRONLY)) < 0) {
++              retval = errno;
++              goto errout;
++      }
++
++      /* Write the superblock out */
++      retval = EXT2_ET_SHORT_WRITE;
++      ret_size = write(fd, buf, fs->blocksize);
++      if (ret_size < 0) {
++              retval = errno;
++              goto errout;
++      }
++      if (ret_size != (int) fs->blocksize)
++              goto errout;
++      memset(buf, 0, fs->blocksize);
++
++      for (i = 1; i < size; i++) {
++              ret_size = write(fd, buf, fs->blocksize);
++              if (ret_size < 0) {
++                      retval = errno;
++                      goto errout;
++              }
++              if (ret_size != (int) fs->blocksize)
++                      goto errout;
++      }
++      close(fd);
++
++      retval = 0;
++errout:
++      ext2fs_free_mem(&buf);
++      return retval;
++}
++
++/*
++ * Helper function for creating the journal using direct I/O routines
++ */
++struct mkjournal_struct {
++      int             num_blocks;
++      int             newblocks;
++      char            *buf;
++      errcode_t       err;
++};
++
++static int mkjournal_proc(ext2_filsys fs,
++                         blk_t        *blocknr,
++                         e2_blkcnt_t  blockcnt,
++                         blk_t        ref_block EXT2FS_ATTR((unused)),
++                         int          ref_offset EXT2FS_ATTR((unused)),
++                         void         *priv_data)
++{
++      struct mkjournal_struct *es = (struct mkjournal_struct *) priv_data;
++      blk_t   new_blk;
++      static blk_t    last_blk = 0;
++      errcode_t       retval;
++      
++      if (*blocknr) {
++              last_blk = *blocknr;
++              return 0;
++      }
++      retval = ext2fs_new_block(fs, last_blk, 0, &new_blk);
++      if (retval) {
++              es->err = retval;
++              return BLOCK_ABORT;
++      }
++      if (blockcnt > 0)
++              es->num_blocks--;
++
++      es->newblocks++;
++      retval = io_channel_write_blk(fs->io, new_blk, 1, es->buf);
++
++      if (blockcnt == 0)
++              memset(es->buf, 0, fs->blocksize);
++
++      if (retval) {
++              es->err = retval;
++              return BLOCK_ABORT;
++      }
++      *blocknr = new_blk;
++      last_blk = new_blk;
++      ext2fs_block_alloc_stats(fs, new_blk, +1);
++
++      if (es->num_blocks == 0)
++              return (BLOCK_CHANGED | BLOCK_ABORT);
++      else
++              return BLOCK_CHANGED;
++      
++}
++
++/*
++ * This function creates a journal using direct I/O routines.
++ */
++static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino,
++                                   blk_t size, int flags)
++{
++      char                    *buf;
++      errcode_t               retval;
++      struct ext2_inode       inode;
++      struct mkjournal_struct es;
++
++      if ((retval = ext2fs_create_journal_superblock(fs, size, flags, &buf)))
++              return retval;
++      
++      if ((retval = ext2fs_read_bitmaps(fs)))
++              return retval;
++
++      if ((retval = ext2fs_read_inode(fs, journal_ino, &inode)))
++              return retval;
++
++      if (inode.i_blocks > 0)
++              return EEXIST;
++
++      es.num_blocks = size;
++      es.newblocks = 0;
++      es.buf = buf;
++      es.err = 0;
++
++      retval = ext2fs_block_iterate2(fs, journal_ino, BLOCK_FLAG_APPEND,
++                                     0, mkjournal_proc, &es);
++      if (es.err) {
++              retval = es.err;
++              goto errout;
++      }
++
++      if ((retval = ext2fs_read_inode(fs, journal_ino, &inode)))
++              goto errout;
++
++      inode.i_size += fs->blocksize * size;
++      inode.i_blocks += (fs->blocksize / 512) * es.newblocks;
++      inode.i_mtime = inode.i_ctime = time(0);
++      inode.i_links_count = 1;
++      inode.i_mode = LINUX_S_IFREG | 0600;
++
++      if ((retval = ext2fs_write_inode(fs, journal_ino, &inode)))
++              goto errout;
++      retval = 0;
++
++      memcpy(fs->super->s_jnl_blocks, inode.i_block, EXT2_N_BLOCKS*4);
++      fs->super->s_jnl_blocks[16] = inode.i_size;
++      fs->super->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS;
++      ext2fs_mark_super_dirty(fs);
++
++errout:
++      ext2fs_free_mem(&buf);
++      return retval;
++}
++
++/*
++ * This function adds a journal device to a filesystem
++ */
++errcode_t ext2fs_add_journal_device(ext2_filsys fs, ext2_filsys journal_dev)
++{
++      struct stat     st;
++      errcode_t       retval;
++      char            buf[1024];
++      journal_superblock_t    *jsb;
++      int             start;
++      __u32           i, nr_users;
++
++      /* Make sure the device exists and is a block device */
++      if (stat(journal_dev->device_name, &st) < 0)
++              return errno;
++      
++      if (!S_ISBLK(st.st_mode))
++              return EXT2_ET_JOURNAL_NOT_BLOCK; /* Must be a block device */
++
++      /* Get the journal superblock */
++      start = 1;
++      if (journal_dev->blocksize == 1024)
++              start++;
++      if ((retval = io_channel_read_blk(journal_dev->io, start, -1024, buf)))
++              return retval;
++
++      jsb = (journal_superblock_t *) buf;
++      if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) ||
++          (jsb->s_header.h_blocktype != (unsigned) ntohl(JFS_SUPERBLOCK_V2)))
++              return EXT2_ET_NO_JOURNAL_SB;
++
++      if (ntohl(jsb->s_blocksize) != (unsigned long) fs->blocksize)
++              return EXT2_ET_UNEXPECTED_BLOCK_SIZE;
++
++      /* Check and see if this filesystem has already been added */
++      nr_users = ntohl(jsb->s_nr_users);
++      for (i=0; i < nr_users; i++) {
++              if (memcmp(fs->super->s_uuid,
++                         &jsb->s_users[i*16], 16) == 0)
++                      break;
++      }
++      if (i >= nr_users) {
++              memcpy(&jsb->s_users[nr_users*16],
++                     fs->super->s_uuid, 16);
++              jsb->s_nr_users = htonl(nr_users+1);
++      }
++
++      /* Writeback the journal superblock */
++      if ((retval = io_channel_write_blk(journal_dev->io, start, -1024, buf)))
++              return retval;
++      
++      fs->super->s_journal_inum = 0;
++      fs->super->s_journal_dev = st.st_rdev;
++      memcpy(fs->super->s_journal_uuid, jsb->s_uuid,
++             sizeof(fs->super->s_journal_uuid));
++      fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
++      ext2fs_mark_super_dirty(fs);
++      return 0;
++}
++
++/*
++ * This function adds a journal inode to a filesystem, using either
++ * POSIX routines if the filesystem is mounted, or using direct I/O
++ * functions if it is not.
++ */
++errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t size, int flags)
++{
++      errcode_t               retval;
++      ext2_ino_t              journal_ino;
++      struct stat             st;
++      char                    jfile[1024];
++      int                     fd, mount_flags, f;
++
++      if ((retval = ext2fs_check_mount_point(fs->device_name, &mount_flags,
++                                             jfile, sizeof(jfile)-10)))
++              return retval;
++
++      if (mount_flags & EXT2_MF_MOUNTED) {
++              strcat(jfile, "/.journal");
++
++              /*
++               * If .../.journal already exists, make sure any 
++               * immutable or append-only flags are cleared.
++               */
++#if defined(HAVE_CHFLAGS) && defined(UF_NODUMP)
++              (void) chflags (jfile, 0);
++#else
++#if HAVE_EXT2_IOCTLS
++              fd = open(jfile, O_RDONLY);
++              if (fd >= 0) {
++                      f = 0;
++                      ioctl(fd, EXT2_IOC_SETFLAGS, &f);
++                      close(fd);
++              }
++#endif
++#endif
++
++              /* Create the journal file */
++              if ((fd = open(jfile, O_CREAT|O_WRONLY, 0600)) < 0)
++                      return errno;
++
++              if ((retval = write_journal_file(fs, jfile, size, flags)))
++                      goto errout;
++              
++              /* Get inode number of the journal file */
++              if (fstat(fd, &st) < 0)
++                      goto errout;
++
++#if defined(HAVE_CHFLAGS) && defined(UF_NODUMP)
++              retval = fchflags (fd, UF_NODUMP|UF_IMMUTABLE);
++#else
++#if HAVE_EXT2_IOCTLS
++              f = EXT2_NODUMP_FL | EXT2_IMMUTABLE_FL;
++              retval = ioctl(fd, EXT2_IOC_SETFLAGS, &f);
++#endif
++#endif
++              if (retval)
++                      goto errout;
++              
++              close(fd);
++              journal_ino = st.st_ino;
++      } else {
++              journal_ino = EXT2_JOURNAL_INO;
++              if ((retval = write_journal_inode(fs, journal_ino,
++                                                size, flags)))
++                      return retval;
++      }
++      
++      fs->super->s_journal_inum = journal_ino;
++      fs->super->s_journal_dev = 0;
++      memset(fs->super->s_journal_uuid, 0,
++             sizeof(fs->super->s_journal_uuid));
++      fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
++
++      ext2fs_mark_super_dirty(fs);
++      return 0;
++errout:
++      close(fd);
++      return retval;
++}
++
++#ifdef DEBUG
++main(int argc, char **argv)
++{
++      errcode_t       retval;
++      char            *device_name;
++      ext2_filsys     fs;
++
++      if (argc < 2) {
++              fprintf(stderr, "Usage: %s filesystem\n", argv[0]);
++              exit(1);
++      }
++      device_name = argv[1];
++      
++      retval = ext2fs_open (device_name, EXT2_FLAG_RW, 0, 0,
++                            unix_io_manager, &fs);
++      if (retval) {
++              com_err(argv[0], retval, "while opening %s", device_name);
++              exit(1);
++      }
++
++      retval = ext2fs_add_journal_inode(fs, 1024);
++      if (retval) {
++              com_err(argv[0], retval, "while adding journal to %s",
++                      device_name);
++              exit(1);
++      }
++      retval = ext2fs_flush(fs);
++      if (retval) {
++              printf("Warning, had trouble writing out superblocks.\n");
++      }
++      ext2fs_close(fs);
++      exit(0);
++      
++}
++#endif
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/namei.c busybox/e2fsprogs/ext2fs/namei.c
+--- busybox-1.00/e2fsprogs/ext2fs/namei.c      1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/namei.c   2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,205 @@
++/*
++ * namei.c --- ext2fs directory lookup operations
++ * 
++ * Copyright (C) 1993, 1994, 1994, 1995 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++
++/* #define NAMEI_DEBUG */
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++static errcode_t open_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t base,
++                          const char *pathname, size_t pathlen, int follow,
++                          int link_count, char *buf, ext2_ino_t *res_inode);
++
++static errcode_t follow_link(ext2_filsys fs, ext2_ino_t root, ext2_ino_t dir,
++                           ext2_ino_t inode, int link_count,
++                           char *buf, ext2_ino_t *res_inode)
++{
++      char *pathname;
++      char *buffer = 0;
++      errcode_t retval;
++      struct ext2_inode ei;
++
++#ifdef NAMEI_DEBUG
++      printf("follow_link: root=%lu, dir=%lu, inode=%lu, lc=%d\n",
++             root, dir, inode, link_count);
++      
++#endif
++      retval = ext2fs_read_inode (fs, inode, &ei);
++      if (retval) return retval;
++      if (!LINUX_S_ISLNK (ei.i_mode)) {
++              *res_inode = inode;
++              return 0;
++      }
++      if (link_count++ > 5) {
++              return EXT2_ET_SYMLINK_LOOP;
++      }
++      if (ext2fs_inode_data_blocks(fs,&ei)) {
++              retval = ext2fs_get_mem(fs->blocksize, &buffer);
++              if (retval)
++                      return retval;
++              retval = io_channel_read_blk(fs->io, ei.i_block[0], 1, buffer);
++              if (retval) {
++                      ext2fs_free_mem(&buffer);
++                      return retval;
++              }
++              pathname = buffer;
++      } else
++              pathname = (char *)&(ei.i_block[0]);
++      retval = open_namei(fs, root, dir, pathname, ei.i_size, 1,
++                          link_count, buf, res_inode);
++      if (buffer)
++              ext2fs_free_mem(&buffer);
++      return retval;
++}
++
++/*
++ * This routine interprets a pathname in the context of the current
++ * directory and the root directory, and returns the inode of the
++ * containing directory, and a pointer to the filename of the file
++ * (pointing into the pathname) and the length of the filename.
++ */
++static errcode_t dir_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t dir,
++                         const char *pathname, int pathlen,
++                         int link_count, char *buf,
++                         const char **name, int *namelen,
++                         ext2_ino_t *res_inode)
++{
++      char c;
++      const char *thisname;
++      int len;
++      ext2_ino_t inode;
++      errcode_t retval;
++
++      if ((c = *pathname) == '/') {
++              dir = root;
++              pathname++;
++              pathlen--;
++      }
++      while (1) {
++              thisname = pathname;
++              for (len=0; --pathlen >= 0;len++) {
++                      c = *(pathname++);
++                      if (c == '/')
++                              break;
++              }
++              if (pathlen < 0)
++                      break;
++              retval = ext2fs_lookup (fs, dir, thisname, len, buf, &inode);
++              if (retval) return retval;
++              retval = follow_link (fs, root, dir, inode,
++                                    link_count, buf, &dir);
++              if (retval) return retval;
++      }
++      *name = thisname;
++      *namelen = len;
++      *res_inode = dir;
++      return 0;
++}
++
++static errcode_t open_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t base,
++                          const char *pathname, size_t pathlen, int follow,
++                          int link_count, char *buf, ext2_ino_t *res_inode)
++{
++      const char *basename;
++      int namelen;
++      ext2_ino_t dir, inode;
++      errcode_t retval;
++
++#ifdef NAMEI_DEBUG
++      printf("open_namei: root=%lu, dir=%lu, path=%*s, lc=%d\n",
++             root, base, pathlen, pathname, link_count);
++#endif
++      retval = dir_namei(fs, root, base, pathname, pathlen,
++                         link_count, buf, &basename, &namelen, &dir);
++      if (retval) return retval;
++      if (!namelen) {                     /* special case: '/usr/' etc */
++              *res_inode=dir;
++              return 0;
++      }
++      retval = ext2fs_lookup (fs, dir, basename, namelen, buf, &inode);
++      if (retval)
++              return retval;
++      if (follow) {
++              retval = follow_link(fs, root, dir, inode, link_count,
++                                   buf, &inode);
++              if (retval)
++                      return retval;
++      }
++#ifdef NAMEI_DEBUG
++      printf("open_namei: (link_count=%d) returns %lu\n",
++             link_count, inode);
++#endif
++      *res_inode = inode;
++      return 0;
++}
++
++errcode_t ext2fs_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
++                     const char *name, ext2_ino_t *inode)
++{
++      char *buf;
++      errcode_t retval;
++      
++      EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
++
++      retval = ext2fs_get_mem(fs->blocksize, &buf);
++      if (retval)
++              return retval;
++      
++      retval = open_namei(fs, root, cwd, name, strlen(name), 0, 0,
++                          buf, inode);
++
++      ext2fs_free_mem(&buf);
++      return retval;
++}
++
++errcode_t ext2fs_namei_follow(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
++                            const char *name, ext2_ino_t *inode)
++{
++      char *buf;
++      errcode_t retval;
++      
++      EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
++
++      retval = ext2fs_get_mem(fs->blocksize, &buf);
++      if (retval)
++              return retval;
++      
++      retval = open_namei(fs, root, cwd, name, strlen(name), 1, 0,
++                          buf, inode);
++
++      ext2fs_free_mem(&buf);
++      return retval;
++}
++
++errcode_t ext2fs_follow_link(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
++                      ext2_ino_t inode, ext2_ino_t *res_inode)
++{
++      char *buf;
++      errcode_t retval;
++      
++      EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
++
++      retval = ext2fs_get_mem(fs->blocksize, &buf);
++      if (retval)
++              return retval;
++
++      retval = follow_link(fs, root, cwd, inode, 0, buf, res_inode);
++
++      ext2fs_free_mem(&buf);
++      return retval;
++}
++
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/native.c busybox/e2fsprogs/ext2fs/native.c
+--- busybox-1.00/e2fsprogs/ext2fs/native.c     1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/native.c  2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,27 @@
++/*
++ * native.c --- returns the ext2_flag for a native byte order
++ * 
++ * Copyright (C) 1996 Theodore Ts'o.
++ * 
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++int ext2fs_native_flag(void)
++{
++#ifdef WORDS_BIGENDIAN
++      return EXT2_FLAG_SWAP_BYTES;
++#else
++      return 0;
++#endif
++}
++
++      
++      
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/newdir.c busybox/e2fsprogs/ext2fs/newdir.c
+--- busybox-1.00/e2fsprogs/ext2fs/newdir.c     1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/newdir.c  2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,72 @@
++/*
++ * newdir.c --- create a new directory block
++ * 
++ * Copyright (C) 1994, 1995 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++#ifndef EXT2_FT_DIR
++#define EXT2_FT_DIR           2
++#endif
++
++/*
++ * Create new directory block
++ */
++errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino,
++                             ext2_ino_t parent_ino, char **block)
++{
++      struct ext2_dir_entry   *dir = NULL;
++      errcode_t               retval;
++      char                    *buf;
++      int                     rec_len;
++      int                     filetype = 0;
++
++      EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
++
++      retval = ext2fs_get_mem(fs->blocksize, &buf);
++      if (retval)
++              return retval;
++      memset(buf, 0, fs->blocksize);
++      dir = (struct ext2_dir_entry *) buf;
++      dir->rec_len = fs->blocksize;
++
++      if (dir_ino) {
++              if (fs->super->s_feature_incompat &
++                  EXT2_FEATURE_INCOMPAT_FILETYPE)
++                      filetype = EXT2_FT_DIR << 8;
++              /*
++               * Set up entry for '.'
++               */
++              dir->inode = dir_ino;
++              dir->name_len = 1 | filetype;
++              dir->name[0] = '.';
++              rec_len = dir->rec_len - EXT2_DIR_REC_LEN(1);
++              dir->rec_len = EXT2_DIR_REC_LEN(1);
++
++              /*
++               * Set up entry for '..'
++               */
++              dir = (struct ext2_dir_entry *) (buf + dir->rec_len);
++              dir->rec_len = rec_len;
++              dir->inode = parent_ino;
++              dir->name_len = 2 | filetype;
++              dir->name[0] = '.';
++              dir->name[1] = '.';
++              
++      }
++      *block = buf;
++      return 0;
++}
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/openfs.c busybox/e2fsprogs/ext2fs/openfs.c
+--- busybox-1.00/e2fsprogs/ext2fs/openfs.c     1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/openfs.c  2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,326 @@
++/*
++ * openfs.c --- open an ext2 filesystem
++ * 
++ * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
++ * 
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <fcntl.h>
++#include <time.h>
++#if HAVE_SYS_STAT_H
++#include <sys/stat.h>
++#endif
++#if HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++
++#include "ext2_fs.h"
++
++
++#include "ext2fs.h"
++#include "e2image.h"
++
++blk_t ext2fs_descriptor_block_loc(ext2_filsys fs, blk_t group_block, dgrp_t i)
++{
++      int     bg;
++      int     has_super = 0;
++      int     ret_blk;
++
++      if (!(fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) ||
++          (i < fs->super->s_first_meta_bg))
++              return (group_block + i + 1);
++
++      bg = (fs->blocksize / sizeof (struct ext2_group_desc)) * i;
++      if (ext2fs_bg_has_super(fs, bg))
++              has_super = 1;
++      ret_blk = (fs->super->s_first_data_block + has_super + 
++                 (bg * fs->super->s_blocks_per_group));
++      /*
++       * If group_block is not the normal value, we're trying to use
++       * the backup group descriptors and superblock --- so use the
++       * alternate location of the second block group in the
++       * metablock group.  Ideally we should be testing each bg
++       * descriptor block individually for correctness, but we don't
++       * have the infrastructure in place to do that.
++       */
++      if (group_block != fs->super->s_first_data_block &&
++          ((ret_blk + fs->super->s_blocks_per_group) <
++           fs->super->s_blocks_count))
++              ret_blk += fs->super->s_blocks_per_group;
++      return ret_blk;
++}
++
++errcode_t ext2fs_open(const char *name, int flags, int superblock,
++                    unsigned int block_size, io_manager manager, 
++                    ext2_filsys *ret_fs)
++{
++      return ext2fs_open2(name, 0, flags, superblock, block_size, 
++                          manager, ret_fs);
++}
++
++/*
++ *  Note: if superblock is non-zero, block-size must also be non-zero.
++ *    Superblock and block_size can be zero to use the default size.
++ *
++ * Valid flags for ext2fs_open()
++ * 
++ *    EXT2_FLAG_RW    - Open the filesystem for read/write.
++ *    EXT2_FLAG_FORCE - Open the filesystem even if some of the
++ *                            features aren't supported.
++ *    EXT2_FLAG_JOURNAL_DEV_OK - Open an ext3 journal device
++ */
++errcode_t ext2fs_open2(const char *name, const char *io_options,
++                     int flags, int superblock,
++                     unsigned int block_size, io_manager manager, 
++                     ext2_filsys *ret_fs)
++{
++      ext2_filsys     fs;
++      errcode_t       retval;
++      unsigned long   i;
++      int             j, groups_per_block, blocks_per_group;
++      blk_t           group_block, blk;
++      char            *dest, *cp;
++      struct ext2_group_desc *gdp;
++      
++      EXT2_CHECK_MAGIC(manager, EXT2_ET_MAGIC_IO_MANAGER);
++
++      retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &fs);
++      if (retval)
++              return retval;
++      
++      memset(fs, 0, sizeof(struct struct_ext2_filsys));
++      fs->magic = EXT2_ET_MAGIC_EXT2FS_FILSYS;
++      fs->flags = flags;
++      fs->umask = 022;
++      retval = ext2fs_get_mem(strlen(name)+1, &fs->device_name);
++      if (retval)
++              goto cleanup;
++      strcpy(fs->device_name, name);
++      cp = strchr(fs->device_name, '?');
++      if (!io_options && cp) {
++              *cp++ = 0;
++              io_options = cp;
++      }
++              
++      retval = manager->open(fs->device_name, 
++                             (flags & EXT2_FLAG_RW) ? IO_FLAG_RW : 0,
++                             &fs->io);
++      if (retval)
++              goto cleanup;
++      if (io_options && 
++          (retval = io_channel_set_options(fs->io, io_options)))
++              goto cleanup;
++      fs->image_io = fs->io;
++      fs->io->app_data = fs;
++      retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->super);
++      if (retval)
++              goto cleanup;
++      if (flags & EXT2_FLAG_IMAGE_FILE) {
++              retval = ext2fs_get_mem(sizeof(struct ext2_image_hdr),
++                                      &fs->image_header);
++              if (retval)
++                      goto cleanup;
++              retval = io_channel_read_blk(fs->io, 0,
++                                           -(int)sizeof(struct ext2_image_hdr),
++                                           fs->image_header);
++              if (retval)
++                      goto cleanup;
++              if (fs->image_header->magic_number != EXT2_ET_MAGIC_E2IMAGE)
++                      return EXT2_ET_MAGIC_E2IMAGE;
++              superblock = 1;
++              block_size = fs->image_header->fs_blocksize;
++      }
++
++      /*
++       * If the user specifies a specific block # for the
++       * superblock, then he/she must also specify the block size!
++       * Otherwise, read the master superblock located at offset
++       * SUPERBLOCK_OFFSET from the start of the partition.
++       *
++       * Note: we only save a backup copy of the superblock if we
++       * are reading the superblock from the primary superblock location.
++       */
++      if (superblock) {
++              if (!block_size) {
++                      retval = EXT2_ET_INVALID_ARGUMENT;
++                      goto cleanup;
++              }
++              io_channel_set_blksize(fs->io, block_size);
++              group_block = superblock;
++              fs->orig_super = 0;
++      } else {
++              io_channel_set_blksize(fs->io, SUPERBLOCK_OFFSET);
++              superblock = 1;
++              group_block = 0;
++              retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->orig_super);
++              if (retval)
++                      goto cleanup;
++      }
++      retval = io_channel_read_blk(fs->io, superblock, -SUPERBLOCK_SIZE,
++                                   fs->super);
++      if (retval)
++              goto cleanup;
++      if (fs->orig_super)
++              memcpy(fs->orig_super, fs->super, SUPERBLOCK_SIZE);
++
++#ifdef EXT2FS_ENABLE_SWAPFS
++      if ((fs->super->s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC)) ||
++          (fs->flags & EXT2_FLAG_SWAP_BYTES)) {
++              fs->flags |= EXT2_FLAG_SWAP_BYTES;
++
++              ext2fs_swap_super(fs->super);
++      }
++#endif
++      
++      if (fs->super->s_magic != EXT2_SUPER_MAGIC) {
++              retval = EXT2_ET_BAD_MAGIC;
++              goto cleanup;
++      }
++      if (fs->super->s_rev_level > EXT2_LIB_CURRENT_REV) {
++              retval = EXT2_ET_REV_TOO_HIGH;
++              goto cleanup;
++      }
++
++      /*
++       * Check for feature set incompatibility
++       */
++      if (!(flags & EXT2_FLAG_FORCE)) {
++              if (fs->super->s_feature_incompat &
++                  ~EXT2_LIB_FEATURE_INCOMPAT_SUPP) {
++                      retval = EXT2_ET_UNSUPP_FEATURE;
++                      goto cleanup;
++              }
++              if ((flags & EXT2_FLAG_RW) &&
++                  (fs->super->s_feature_ro_compat &
++                   ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP)) {
++                      retval = EXT2_ET_RO_UNSUPP_FEATURE;
++                      goto cleanup;
++              }
++              if (!(flags & EXT2_FLAG_JOURNAL_DEV_OK) &&
++                  (fs->super->s_feature_incompat &
++                   EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
++                      retval = EXT2_ET_UNSUPP_FEATURE;
++                      goto cleanup;
++              }
++      }
++      
++      fs->blocksize = EXT2_BLOCK_SIZE(fs->super);
++      if (fs->blocksize == 0) {
++              retval = EXT2_ET_CORRUPT_SUPERBLOCK;
++              goto cleanup;
++      }
++      fs->fragsize = EXT2_FRAG_SIZE(fs->super);
++      fs->inode_blocks_per_group = ((fs->super->s_inodes_per_group *
++                                     EXT2_INODE_SIZE(fs->super) +
++                                     EXT2_BLOCK_SIZE(fs->super) - 1) /
++                                    EXT2_BLOCK_SIZE(fs->super));
++      if (block_size) {
++              if (block_size != fs->blocksize) {
++                      retval = EXT2_ET_UNEXPECTED_BLOCK_SIZE;
++                      goto cleanup;
++              }
++      }
++      /*
++       * Set the blocksize to the filesystem's blocksize.
++       */
++      io_channel_set_blksize(fs->io, fs->blocksize);
++
++      /*
++       * If this is an external journal device, don't try to read
++       * the group descriptors, because they're not there.
++       */
++      if (fs->super->s_feature_incompat &
++          EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
++              fs->group_desc_count = 0;
++              *ret_fs = fs;
++              return 0;
++      }
++      
++      /*
++       * Read group descriptors
++       */
++      blocks_per_group = EXT2_BLOCKS_PER_GROUP(fs->super);
++      if (blocks_per_group == 0 ||
++          blocks_per_group > EXT2_MAX_BLOCKS_PER_GROUP(fs->super) ||
++          fs->inode_blocks_per_group > EXT2_MAX_INODES_PER_GROUP(fs->super)) {
++              retval = EXT2_ET_CORRUPT_SUPERBLOCK;
++              goto cleanup;
++      }
++      fs->group_desc_count = (fs->super->s_blocks_count -
++                              fs->super->s_first_data_block +
++                              blocks_per_group - 1) / blocks_per_group;
++      fs->desc_blocks = (fs->group_desc_count +
++                         EXT2_DESC_PER_BLOCK(fs->super) - 1)
++              / EXT2_DESC_PER_BLOCK(fs->super);
++      retval = ext2fs_get_mem(fs->desc_blocks * fs->blocksize,
++                              &fs->group_desc);
++      if (retval)
++              goto cleanup;
++      if (!group_block)
++              group_block = fs->super->s_first_data_block;
++      dest = (char *) fs->group_desc;
++      groups_per_block = fs->blocksize / sizeof(struct ext2_group_desc);
++      for (i=0 ; i < fs->desc_blocks; i++) {
++              blk = ext2fs_descriptor_block_loc(fs, group_block, i);
++              retval = io_channel_read_blk(fs->io, blk, 1, dest);
++              if (retval)
++                      goto cleanup;
++#ifdef EXT2FS_ENABLE_SWAPFS
++              if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
++                      gdp = (struct ext2_group_desc *) dest;
++                      for (j=0; j < groups_per_block; j++)
++                              ext2fs_swap_group_desc(gdp++);
++              }
++#endif
++              dest += fs->blocksize;
++      }
++
++      *ret_fs = fs;
++      return 0;
++cleanup:
++      ext2fs_free(fs);
++      return retval;
++}
++
++/*
++ * Set/get the filesystem data I/O channel.
++ * 
++ * These functions are only valid if EXT2_FLAG_IMAGE_FILE is true.
++ */
++errcode_t ext2fs_get_data_io(ext2_filsys fs, io_channel *old_io)
++{
++      if ((fs->flags & EXT2_FLAG_IMAGE_FILE) == 0)
++              return EXT2_ET_NOT_IMAGE_FILE;
++      if (old_io) {
++              *old_io = (fs->image_io == fs->io) ? 0 : fs->io;
++      }
++      return 0;
++}
++
++errcode_t ext2fs_set_data_io(ext2_filsys fs, io_channel new_io)
++{
++      if ((fs->flags & EXT2_FLAG_IMAGE_FILE) == 0)
++              return EXT2_ET_NOT_IMAGE_FILE;
++      fs->io = new_io ? new_io : fs->image_io;
++      return 0;
++}
++
++errcode_t ext2fs_rewrite_to_io(ext2_filsys fs, io_channel new_io)
++{
++      if ((fs->flags & EXT2_FLAG_IMAGE_FILE) == 0)
++              return EXT2_ET_NOT_IMAGE_FILE;
++      fs->io = fs->image_io = new_io;
++      fs->flags |= EXT2_FLAG_DIRTY | EXT2_FLAG_RW | 
++              EXT2_FLAG_BB_DIRTY | EXT2_FLAG_IB_DIRTY;
++      fs->flags &= ~EXT2_FLAG_IMAGE_FILE;
++      return 0;
++}
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/read_bb.c busybox/e2fsprogs/ext2fs/read_bb.c
+--- busybox-1.00/e2fsprogs/ext2fs/read_bb.c    1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/read_bb.c 2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,97 @@
++/*
++ * read_bb --- read the bad blocks inode
++ *
++ * Copyright (C) 1994 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <fcntl.h>
++#include <time.h>
++#if HAVE_SYS_STAT_H
++#include <sys/stat.h>
++#endif
++#if HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++struct read_bb_record {
++      ext2_badblocks_list     bb_list;
++      errcode_t       err;
++};
++
++/*
++ * Helper function for ext2fs_read_bb_inode()
++ */
++#ifdef __TURBOC__
++ #pragma argsused
++#endif
++static int mark_bad_block(ext2_filsys fs, blk_t *block_nr,
++                        e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)), 
++                        blk_t ref_block EXT2FS_ATTR((unused)),
++                        int ref_offset EXT2FS_ATTR((unused)), 
++                        void *priv_data)
++{
++      struct read_bb_record *rb = (struct read_bb_record *) priv_data;
++      
++      if (blockcnt < 0)
++              return 0;
++      
++      if ((*block_nr < fs->super->s_first_data_block) ||
++          (*block_nr >= fs->super->s_blocks_count))
++              return 0;       /* Ignore illegal blocks */
++
++      rb->err = ext2fs_badblocks_list_add(rb->bb_list, *block_nr);
++      if (rb->err)
++              return BLOCK_ABORT;
++      return 0;
++}
++
++/*
++ * Reads the current bad blocks from the bad blocks inode.
++ */
++errcode_t ext2fs_read_bb_inode(ext2_filsys fs, ext2_badblocks_list *bb_list)
++{
++      errcode_t       retval;
++      struct read_bb_record rb;
++      struct ext2_inode inode;
++      blk_t   numblocks;
++
++      EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
++
++      if (!*bb_list) {
++              retval = ext2fs_read_inode(fs, EXT2_BAD_INO, &inode);
++              if (retval)
++                      return retval;
++              if (inode.i_blocks < 500)
++                      numblocks = (inode.i_blocks /
++                                   (fs->blocksize / 512)) + 20;
++              else
++                      numblocks = 500;
++              retval = ext2fs_badblocks_list_create(bb_list, numblocks);
++              if (retval)
++                      return retval;
++      }
++
++      rb.bb_list = *bb_list;
++      rb.err = 0;
++      retval = ext2fs_block_iterate2(fs, EXT2_BAD_INO, 0, 0,
++                                    mark_bad_block, &rb);
++      if (retval)
++              return retval;
++
++      return rb.err;
++}
++
++
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/read_bb_file.c busybox/e2fsprogs/ext2fs/read_bb_file.c
+--- busybox-1.00/e2fsprogs/ext2fs/read_bb_file.c       1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/read_bb_file.c    2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,97 @@
++/*
++ * read_bb_file.c --- read a list of bad blocks from a FILE *
++ *
++ * Copyright (C) 1994, 1995, 2000 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <fcntl.h>
++#include <time.h>
++#if HAVE_SYS_STAT_H
++#include <sys/stat.h>
++#endif
++#if HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++/*
++ * Reads a list of bad blocks from  a FILE *
++ */
++errcode_t ext2fs_read_bb_FILE2(ext2_filsys fs, FILE *f, 
++                             ext2_badblocks_list *bb_list,
++                             void *priv_data,
++                             void (*invalid)(ext2_filsys fs,
++                                             blk_t blk,
++                                             char *badstr,
++                                             void *priv_data))
++{
++      errcode_t       retval;
++      blk_t           blockno;
++      int             count;
++      char            buf[128];
++
++      if (fs)
++              EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
++
++      if (!*bb_list) {
++              retval = ext2fs_badblocks_list_create(bb_list, 10);
++              if (retval)
++                      return retval;
++      }
++
++      while (!feof (f)) {
++              if (fgets(buf, sizeof(buf), f) == NULL)
++                      break;
++              count = sscanf(buf, "%u", &blockno);
++              if (count <= 0)
++                      continue;
++              if (fs &&
++                  ((blockno < fs->super->s_first_data_block) ||
++                  (blockno >= fs->super->s_blocks_count))) {
++                      if (invalid)
++                              (invalid)(fs, blockno, buf, priv_data);
++                      continue;
++              }
++              retval = ext2fs_badblocks_list_add(*bb_list, blockno);
++              if (retval)
++                      return retval;
++      }
++      return 0;
++}
++
++static void call_compat_invalid(ext2_filsys fs, blk_t blk,
++                              char *badstr EXT2FS_ATTR((unused)), 
++                              void *priv_data)
++{
++      void (*invalid)(ext2_filsys, blk_t);
++
++      invalid = (void (*)(ext2_filsys, blk_t)) priv_data;
++      if (invalid)
++              invalid(fs, blk);
++}
++
++
++/*
++ * Reads a list of bad blocks from  a FILE *
++ */
++errcode_t ext2fs_read_bb_FILE(ext2_filsys fs, FILE *f, 
++                            ext2_badblocks_list *bb_list,
++                            void (*invalid)(ext2_filsys fs, blk_t blk))
++{
++      return ext2fs_read_bb_FILE2(fs, f, bb_list, (void *) invalid,
++                                  call_compat_invalid);
++}
++
++
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/res_gdt.c busybox/e2fsprogs/ext2fs/res_gdt.c
+--- busybox-1.00/e2fsprogs/ext2fs/res_gdt.c    1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/res_gdt.c 2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,220 @@
++/*
++ * res_gdt.c --- reserve blocks for growing the group descriptor table
++ *               during online resizing.
++ *
++ * Copyright (C) 2002 Andreas Dilger
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <string.h>
++#include <time.h>
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++/*
++ * Iterate through the groups which hold BACKUP superblock/GDT copies in an
++ * ext3 filesystem.  The counters should be initialized to 1, 5, and 7 before
++ * calling this for the first time.  In a sparse filesystem it will be the
++ * sequence of powers of 3, 5, and 7: 1, 3, 5, 7, 9, 25, 27, 49, 81, ...
++ * For a non-sparse filesystem it will be every group: 1, 2, 3, 4, ...
++ */
++static unsigned int list_backups(ext2_filsys fs, unsigned int *three,
++                               unsigned int *five, unsigned int *seven)
++{
++      unsigned int *min = three;
++      int mult = 3;
++      unsigned int ret;
++
++      if (!(fs->super->s_feature_ro_compat &
++            EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)) {
++              ret = *min;
++              *min += 1;
++              return ret;
++      }
++
++      if (*five < *min) {
++              min = five;
++              mult = 5;
++      }
++      if (*seven < *min) {
++              min = seven;
++              mult = 7;
++      }
++
++      ret = *min;
++      *min *= mult;
++
++      return ret;
++}
++
++/*
++ * This code assumes that the reserved blocks have already been marked in-use
++ * during ext2fs_initialize(), so that they are not allocated for other
++ * uses before we can add them to the resize inode (which has to come
++ * after the creation of the inode table).
++ */
++errcode_t ext2fs_create_resize_inode(ext2_filsys fs)
++{
++      errcode_t               retval, retval2;
++      struct ext2_super_block *sb;
++      struct ext2_inode       inode;
++      __u32                   *dindir_buf, *gdt_buf;
++      int                     rsv_add;
++      unsigned long long      apb, inode_size;
++      blk_t                   dindir_blk, rsv_off, gdt_off, gdt_blk;
++      int                     dindir_dirty = 0, inode_dirty = 0;
++
++      EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
++
++      sb = fs->super;
++
++      retval = ext2fs_get_mem(2 * fs->blocksize, (void **)&dindir_buf);
++      if (retval)
++              goto out_free;
++      gdt_buf = (__u32 *)((char *)dindir_buf + fs->blocksize);
++
++      retval = ext2fs_read_inode(fs, EXT2_RESIZE_INO, &inode);
++      if (retval)
++              goto out_free;
++
++      /* Maximum possible file size (we donly use the dindirect blocks) */
++      apb = EXT2_ADDR_PER_BLOCK(sb);
++      rsv_add = fs->blocksize / 512;
++      if ((dindir_blk = inode.i_block[EXT2_DIND_BLOCK])) {
++#ifdef RES_GDT_DEBUG
++              printf("reading GDT dindir %u\n", dindir_blk);
++#endif
++              retval = ext2fs_read_ind_block(fs, dindir_blk, dindir_buf);
++              if (retval)
++                      goto out_inode;
++      } else {
++              blk_t goal = 3 + sb->s_reserved_gdt_blocks +
++                      fs->desc_blocks + fs->inode_blocks_per_group;
++
++              retval = ext2fs_alloc_block(fs, goal, 0, &dindir_blk);
++              if (retval)
++                      goto out_free;
++              inode.i_mode = LINUX_S_IFREG | 0600;
++              inode.i_links_count = 1;
++              inode.i_block[EXT2_DIND_BLOCK] = dindir_blk;
++              inode.i_blocks = rsv_add;
++              memset(dindir_buf, 0, fs->blocksize);
++#ifdef RES_GDT_DEBUG
++              printf("allocated GDT dindir %u\n", dindir_blk);
++#endif
++              dindir_dirty = inode_dirty = 1;
++              inode_size = apb*apb + apb + EXT2_NDIR_BLOCKS;
++              inode_size *= fs->blocksize;
++              inode.i_size = inode_size & 0xFFFFFFFF;
++              inode.i_size_high = (inode_size >> 32) & 0xFFFFFFFF;
++              if(inode.i_size_high) {
++                      sb->s_feature_ro_compat |=
++                              EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
++              }
++              inode.i_ctime = time(0);
++      }
++
++      for (rsv_off = 0, gdt_off = fs->desc_blocks,
++           gdt_blk = sb->s_first_data_block + 1 + fs->desc_blocks;
++           rsv_off < sb->s_reserved_gdt_blocks;
++           rsv_off++, gdt_off++, gdt_blk++) {
++              unsigned int three = 1, five = 5, seven = 7;
++              unsigned int grp, last = 0;
++              int gdt_dirty = 0;
++
++              gdt_off %= apb;
++              if (!dindir_buf[gdt_off]) {
++                      /* FIXME XXX XXX
++                      blk_t new_blk;
++
++                      retval = ext2fs_new_block(fs, gdt_blk, 0, &new_blk);
++                      if (retval)
++                              goto out_free;
++                      if (new_blk != gdt_blk) {
++                              // XXX free block
++                              retval = -1; // XXX
++                      }
++                      */
++                      gdt_dirty = dindir_dirty = inode_dirty = 1;
++                      memset(gdt_buf, 0, fs->blocksize);
++                      dindir_buf[gdt_off] = gdt_blk;
++                      inode.i_blocks += rsv_add;
++#ifdef RES_GDT_DEBUG
++                      printf("added primary GDT block %u at %u[%u]\n",
++                             gdt_blk, dindir_blk, gdt_off);
++#endif
++              } else if (dindir_buf[gdt_off] == gdt_blk) {
++#ifdef RES_GDT_DEBUG
++                      printf("reading primary GDT block %u\n", gdt_blk);
++#endif
++                      retval = ext2fs_read_ind_block(fs, gdt_blk, gdt_buf);
++                      if (retval)
++                              goto out_dindir;
++              } else {
++#ifdef RES_GDT_DEBUG
++                      printf("bad primary GDT %u != %u at %u[%u]\n",
++                             dindir_buf[gdt_off], gdt_blk,dindir_blk,gdt_off);
++#endif
++                      retval = EXT2_ET_RESIZE_INODE_CORRUPT;
++                      goto out_dindir;
++              }
++
++              while ((grp = list_backups(fs, &three, &five, &seven)) <
++                     fs->group_desc_count) {
++                      blk_t expect = gdt_blk + grp * sb->s_blocks_per_group;
++
++                      if (!gdt_buf[last]) {
++#ifdef RES_GDT_DEBUG
++                              printf("added backup GDT %u grp %u@%u[%u]\n",
++                                     expect, grp, gdt_blk, last);
++#endif
++                              gdt_buf[last] = expect;
++                              inode.i_blocks += rsv_add;
++                              gdt_dirty = inode_dirty = 1;
++                      } else if (gdt_buf[last] != expect) {
++#ifdef RES_GDT_DEBUG
++                              printf("bad backup GDT %u != %u at %u[%u]\n",
++                                     gdt_buf[last], expect, gdt_blk, last);
++#endif
++                              retval = EXT2_ET_RESIZE_INODE_CORRUPT;
++                              goto out_dindir;
++                      }
++                      last++;
++              }
++              if (gdt_dirty) {
++#ifdef RES_GDT_DEBUG
++                      printf("writing primary GDT block %u\n", gdt_blk);
++#endif
++                      retval = ext2fs_write_ind_block(fs, gdt_blk, gdt_buf);
++                      if (retval)
++                              goto out_dindir;
++              }
++      }
++
++out_dindir:
++      if (dindir_dirty) {
++              retval2 = ext2fs_write_ind_block(fs, dindir_blk, dindir_buf);
++              if (!retval)
++                      retval = retval2;
++      }
++out_inode:
++#ifdef RES_GDT_DEBUG
++      printf("inode.i_blocks = %u, i_size = %u\n", inode.i_blocks,
++             inode.i_size);
++#endif
++      if (inode_dirty) {
++              inode.i_atime = inode.i_mtime = time(0);
++              retval2 = ext2fs_write_inode(fs, EXT2_RESIZE_INO, &inode);
++              if (!retval)
++                      retval = retval2;
++      }
++out_free:
++      ext2fs_free_mem((void **)&dindir_buf);
++      return retval;
++}
++
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/rs_bitmap.c busybox/e2fsprogs/ext2fs/rs_bitmap.c
+--- busybox-1.00/e2fsprogs/ext2fs/rs_bitmap.c  1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/rs_bitmap.c       2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,106 @@
++/*
++ * rs_bitmap.c --- routine for changing the size of a bitmap
++ *
++ * Copyright (C) 1996, 1997 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <fcntl.h>
++#include <time.h>
++#ifdef HAVE_SYS_STAT_H
++#include <sys/stat.h>
++#endif
++#ifdef HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++errcode_t ext2fs_resize_generic_bitmap(__u32 new_end, __u32 new_real_end,
++                                     ext2fs_generic_bitmap bmap)
++{
++      errcode_t       retval;
++      size_t          size, new_size;
++      __u32           bitno;
++
++      if (!bmap)
++              return EXT2_ET_INVALID_ARGUMENT;
++
++      EXT2_CHECK_MAGIC(bmap, EXT2_ET_MAGIC_GENERIC_BITMAP);
++
++      /*
++       * If we're expanding the bitmap, make sure all of the new
++       * parts of the bitmap are zero.
++       */
++      if (new_end > bmap->end) {
++              bitno = bmap->real_end;
++              if (bitno > new_end)
++                      bitno = new_end;
++              for (; bitno > bmap->end; bitno--)
++                      ext2fs_clear_bit(bitno - bmap->start, bmap->bitmap);
++      }
++      if (new_real_end == bmap->real_end) {
++              bmap->end = new_end;
++              return 0;
++      }
++      
++      size = ((bmap->real_end - bmap->start) / 8) + 1;
++      new_size = ((new_real_end - bmap->start) / 8) + 1;
++
++      if (size != new_size) {
++              retval = ext2fs_resize_mem(size, new_size, &bmap->bitmap);
++              if (retval)
++                      return retval;
++      }
++      if (new_size > size)
++              memset(bmap->bitmap + size, 0, new_size - size);
++
++      bmap->end = new_end;
++      bmap->real_end = new_real_end;
++      return 0;
++}
++
++errcode_t ext2fs_resize_inode_bitmap(__u32 new_end, __u32 new_real_end,
++                                   ext2fs_inode_bitmap bmap)
++{
++      errcode_t       retval;
++      
++      if (!bmap)
++              return EXT2_ET_INVALID_ARGUMENT;
++
++      EXT2_CHECK_MAGIC(bmap, EXT2_ET_MAGIC_INODE_BITMAP);
++
++      bmap->magic = EXT2_ET_MAGIC_GENERIC_BITMAP;
++      retval = ext2fs_resize_generic_bitmap(new_end, new_real_end,
++                                            bmap);
++      bmap->magic = EXT2_ET_MAGIC_INODE_BITMAP;
++      return retval;
++}
++
++errcode_t ext2fs_resize_block_bitmap(__u32 new_end, __u32 new_real_end,
++                                   ext2fs_block_bitmap bmap)
++{
++      errcode_t       retval;
++      
++      if (!bmap)
++              return EXT2_ET_INVALID_ARGUMENT;
++
++      EXT2_CHECK_MAGIC(bmap, EXT2_ET_MAGIC_BLOCK_BITMAP);
++
++      bmap->magic = EXT2_ET_MAGIC_GENERIC_BITMAP;
++      retval = ext2fs_resize_generic_bitmap(new_end, new_real_end,
++                                            bmap);
++      bmap->magic = EXT2_ET_MAGIC_BLOCK_BITMAP;
++      return retval;
++}
++
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/rw_bitmaps.c busybox/e2fsprogs/ext2fs/rw_bitmaps.c
+--- busybox-1.00/e2fsprogs/ext2fs/rw_bitmaps.c 1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/rw_bitmaps.c      2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,300 @@
++/*
++ * rw_bitmaps.c --- routines to read and write the  inode and block bitmaps.
++ *
++ * Copyright (C) 1993, 1994, 1994, 1996 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <fcntl.h>
++#include <time.h>
++#ifdef HAVE_SYS_STAT_H
++#include <sys/stat.h>
++#endif
++#ifdef HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++#include "e2image.h"
++
++#if defined(__powerpc__) && defined(EXT2FS_ENABLE_SWAPFS)
++/*
++ * On the PowerPC, the big-endian variant of the ext2 filesystem
++ * has its bitmaps stored as 32-bit words with bit 0 as the LSB
++ * of each word.  Thus a bitmap with only bit 0 set would be, as
++ * a string of bytes, 00 00 00 01 00 ...
++ * To cope with this, we byte-reverse each word of a bitmap if
++ * we have a big-endian filesystem, that is, if we are *not*
++ * byte-swapping other word-sized numbers.
++ */
++#define EXT2_BIG_ENDIAN_BITMAPS
++#endif
++
++#ifdef EXT2_BIG_ENDIAN_BITMAPS
++static void ext2fs_swap_bitmap(ext2_filsys fs, char *bitmap, int nbytes)
++{
++      __u32 *p = (__u32 *) bitmap;
++      int n;
++              
++      for (n = nbytes / sizeof(__u32); n > 0; --n, ++p)
++              *p = ext2fs_swab32(*p);
++}
++#endif
++
++errcode_t ext2fs_write_inode_bitmap(ext2_filsys fs)
++{
++      dgrp_t          i;
++      size_t          nbytes;
++      errcode_t       retval;
++      char * inode_bitmap = fs->inode_map->bitmap;
++      char * bitmap_block = NULL;
++      blk_t           blk;
++
++      EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
++
++      if (!(fs->flags & EXT2_FLAG_RW))
++              return EXT2_ET_RO_FILSYS;
++      if (!inode_bitmap)
++              return 0;
++      nbytes = (size_t) ((EXT2_INODES_PER_GROUP(fs->super)+7) / 8);
++      
++      retval = ext2fs_get_mem(fs->blocksize, &bitmap_block);
++      if (retval)
++              return retval;
++      memset(bitmap_block, 0xff, fs->blocksize);
++      for (i = 0; i < fs->group_desc_count; i++) {
++              memcpy(bitmap_block, inode_bitmap, nbytes);
++              blk = fs->group_desc[i].bg_inode_bitmap;
++              if (blk) {
++#ifdef EXT2_BIG_ENDIAN_BITMAPS
++                      if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
++                            (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)))
++                              ext2fs_swap_bitmap(fs, bitmap_block, nbytes);
++#endif
++                      retval = io_channel_write_blk(fs->io, blk, 1,
++                                                    bitmap_block);
++                      if (retval)
++                              return EXT2_ET_INODE_BITMAP_WRITE;
++              }
++              inode_bitmap += nbytes;
++      }
++      fs->flags &= ~EXT2_FLAG_IB_DIRTY;
++      ext2fs_free_mem(&bitmap_block);
++      return 0;
++}
++
++errcode_t ext2fs_write_block_bitmap (ext2_filsys fs)
++{
++      dgrp_t          i;
++      unsigned int    j;
++      int             nbytes;
++      unsigned int    nbits;
++      errcode_t       retval;
++      char * block_bitmap = fs->block_map->bitmap;
++      char * bitmap_block = NULL;
++      blk_t           blk;
++
++      EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
++
++      if (!(fs->flags & EXT2_FLAG_RW))
++              return EXT2_ET_RO_FILSYS;
++      if (!block_bitmap)
++              return 0;
++      nbytes = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
++      retval = ext2fs_get_mem(fs->blocksize, &bitmap_block);
++      if (retval)
++              return retval;
++      memset(bitmap_block, 0xff, fs->blocksize);
++      for (i = 0; i < fs->group_desc_count; i++) {
++              memcpy(bitmap_block, block_bitmap, nbytes);
++              if (i == fs->group_desc_count - 1) {
++                      /* Force bitmap padding for the last group */
++                      nbits = ((fs->super->s_blocks_count
++                                - fs->super->s_first_data_block)
++                               % EXT2_BLOCKS_PER_GROUP(fs->super));
++                      if (nbits)
++                              for (j = nbits; j < fs->blocksize * 8; j++)
++                                      ext2fs_set_bit(j, bitmap_block);
++              }
++              blk = fs->group_desc[i].bg_block_bitmap;
++              if (blk) {
++#ifdef EXT2_BIG_ENDIAN_BITMAPS
++                      if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
++                            (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)))
++                              ext2fs_swap_bitmap(fs, bitmap_block, nbytes);
++#endif
++                      retval = io_channel_write_blk(fs->io, blk, 1,
++                                                    bitmap_block);
++                      if (retval)
++                              return EXT2_ET_BLOCK_BITMAP_WRITE;
++              }
++              block_bitmap += nbytes;
++      }
++      fs->flags &= ~EXT2_FLAG_BB_DIRTY;
++      ext2fs_free_mem(&bitmap_block);
++      return 0;
++}
++
++static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block)
++{
++      dgrp_t i;
++      char *block_bitmap = 0, *inode_bitmap = 0;
++      char *buf;
++      errcode_t retval;
++      int block_nbytes = (int) EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
++      int inode_nbytes = (int) EXT2_INODES_PER_GROUP(fs->super) / 8;
++      blk_t   blk;
++
++      EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
++
++      fs->write_bitmaps = ext2fs_write_bitmaps;
++
++      retval = ext2fs_get_mem(strlen(fs->device_name) + 80, &buf);
++      if (retval)
++              return retval;
++      if (do_block) {
++              if (fs->block_map)
++                      ext2fs_free_block_bitmap(fs->block_map);
++              sprintf(buf, "block bitmap for %s", fs->device_name);
++              retval = ext2fs_allocate_block_bitmap(fs, buf, &fs->block_map);
++              if (retval)
++                      goto cleanup;
++              block_bitmap = fs->block_map->bitmap;
++      }
++      if (do_inode) {
++              if (fs->inode_map)
++                      ext2fs_free_inode_bitmap(fs->inode_map);
++              sprintf(buf, "inode bitmap for %s", fs->device_name);
++              retval = ext2fs_allocate_inode_bitmap(fs, buf, &fs->inode_map);
++              if (retval)
++                      goto cleanup;
++              inode_bitmap = fs->inode_map->bitmap;
++      }
++      ext2fs_free_mem(&buf);
++
++      if (fs->flags & EXT2_FLAG_IMAGE_FILE) {
++              if (inode_bitmap) {
++                      blk = (fs->image_header->offset_inodemap /
++                             fs->blocksize);
++                      retval = io_channel_read_blk(fs->image_io, blk,
++                           -(inode_nbytes * fs->group_desc_count),
++                           inode_bitmap);
++                      if (retval)
++                              goto cleanup;
++              }
++              if (block_bitmap) {
++                      blk = (fs->image_header->offset_blockmap /
++                             fs->blocksize);
++                      retval = io_channel_read_blk(fs->image_io, blk, 
++                           -(block_nbytes * fs->group_desc_count),
++                           block_bitmap);
++                      if (retval)
++                              goto cleanup;
++              }
++              return 0;
++      }
++
++      for (i = 0; i < fs->group_desc_count; i++) {
++              if (block_bitmap) {
++                      blk = fs->group_desc[i].bg_block_bitmap;
++                      if (blk) {
++                              retval = io_channel_read_blk(fs->io, blk,
++                                           -block_nbytes, block_bitmap);
++                              if (retval) {
++                                      retval = EXT2_ET_BLOCK_BITMAP_READ;
++                                      goto cleanup;
++                              }
++#ifdef EXT2_BIG_ENDIAN_BITMAPS
++                              if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
++                                    (fs->flags & EXT2_FLAG_SWAP_BYTES_READ)))
++                                      ext2fs_swap_bitmap(fs, block_bitmap, block_nbytes);
++#endif
++                      } else
++                              memset(block_bitmap, 0, block_nbytes);
++                      block_bitmap += block_nbytes;
++              }
++              if (inode_bitmap) {
++                      blk = fs->group_desc[i].bg_inode_bitmap;
++                      if (blk) {
++                              retval = io_channel_read_blk(fs->io, blk,
++                                           -inode_nbytes, inode_bitmap);
++                              if (retval) {
++                                      retval = EXT2_ET_INODE_BITMAP_READ;
++                                      goto cleanup;
++                              }
++#ifdef EXT2_BIG_ENDIAN_BITMAPS
++                              if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
++                                    (fs->flags & EXT2_FLAG_SWAP_BYTES_READ)))
++                                      ext2fs_swap_bitmap(fs, inode_bitmap, inode_nbytes);
++#endif
++                      } else
++                              memset(inode_bitmap, 0, inode_nbytes);
++                      inode_bitmap += inode_nbytes;
++              }
++      }
++      return 0;
++      
++cleanup:
++      if (do_block) {
++              ext2fs_free_mem(&fs->block_map);
++              fs->block_map = 0;
++      }
++      if (do_inode) {
++              ext2fs_free_mem(&fs->inode_map);
++              fs->inode_map = 0;
++      }
++      if (buf)
++              ext2fs_free_mem(&buf);
++      return retval;
++}
++
++errcode_t ext2fs_read_inode_bitmap (ext2_filsys fs)
++{
++      return read_bitmaps(fs, 1, 0);
++}
++
++errcode_t ext2fs_read_block_bitmap(ext2_filsys fs)
++{
++      return read_bitmaps(fs, 0, 1);
++}
++
++errcode_t ext2fs_read_bitmaps(ext2_filsys fs)
++{
++
++      EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
++
++      if (fs->inode_map && fs->block_map)
++              return 0;
++
++      return read_bitmaps(fs, !fs->inode_map, !fs->block_map);
++}
++
++errcode_t ext2fs_write_bitmaps(ext2_filsys fs)
++{
++      errcode_t       retval;
++
++      EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
++
++      if (fs->block_map && ext2fs_test_bb_dirty(fs)) {
++              retval = ext2fs_write_block_bitmap(fs);
++              if (retval)
++                      return retval;
++      }
++      if (fs->inode_map && ext2fs_test_ib_dirty(fs)) {
++              retval = ext2fs_write_inode_bitmap(fs);
++              if (retval)
++                      return retval;
++      }
++      return 0;
++}     
++
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/sparse.c busybox/e2fsprogs/ext2fs/sparse.c
+--- busybox-1.00/e2fsprogs/ext2fs/sparse.c     1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/sparse.c  2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,78 @@
++/*
++ * sparse.c --- find the groups in an ext2 filesystem with metadata backups
++ *
++ * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
++ * Copyright (C) 2002 Andreas Dilger.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++
++#include "ext2_fs.h"
++#include "ext2fsP.h"
++
++static int test_root(int a, int b)
++{
++      if (a == 0)
++              return 1;
++      while (1) {
++              if (a == 1)
++                      return 1;
++              if (a % b)
++                      return 0;
++              a = a / b;
++      }
++}
++
++int ext2fs_bg_has_super(ext2_filsys fs, int group_block)
++{
++      if (!(fs->super->s_feature_ro_compat &
++            EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER))
++              return 1;
++
++      if (test_root(group_block, 3) || (test_root(group_block, 5)) ||
++          test_root(group_block, 7))
++              return 1;
++
++      return 0;
++}
++
++/*
++ * Iterate through the groups which hold BACKUP superblock/GDT copies in an
++ * ext3 filesystem.  The counters should be initialized to 1, 5, and 7 before
++ * calling this for the first time.  In a sparse filesystem it will be the
++ * sequence of powers of 3, 5, and 7: 1, 3, 5, 7, 9, 25, 27, 49, 81, ...
++ * For a non-sparse filesystem it will be every group: 1, 2, 3, 4, ...
++ */
++unsigned int ext2fs_list_backups(ext2_filsys fs, unsigned int *three,
++                               unsigned int *five, unsigned int *seven)
++{
++      unsigned int *min = three;
++      int mult = 3;
++      unsigned int ret;
++
++      if (!(fs->super->s_feature_ro_compat &
++            EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)) {
++              ret = *min;
++              *min += 1;
++              return ret;
++      }
++
++      if (*five < *min) {
++              min = five;
++              mult = 5;
++      }
++      if (*seven < *min) {
++              min = seven;
++              mult = 7;
++      }
++
++      ret = *min;
++      *min *= mult;
++
++      return ret;
++}
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/swapfs.c busybox/e2fsprogs/ext2fs/swapfs.c
+--- busybox-1.00/e2fsprogs/ext2fs/swapfs.c     1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/swapfs.c  2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,237 @@
++/*
++ * swapfs.c --- swap ext2 filesystem data structures
++ * 
++ * Copyright (C) 1995, 1996, 2002 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <string.h>
++#include <time.h>
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++#include <ext2fs/ext2_ext_attr.h>
++
++#ifdef EXT2FS_ENABLE_SWAPFS
++void ext2fs_swap_super(struct ext2_super_block * sb)
++{
++      int i;
++      sb->s_inodes_count = ext2fs_swab32(sb->s_inodes_count);
++      sb->s_blocks_count = ext2fs_swab32(sb->s_blocks_count);
++      sb->s_r_blocks_count = ext2fs_swab32(sb->s_r_blocks_count);
++      sb->s_free_blocks_count = ext2fs_swab32(sb->s_free_blocks_count);
++      sb->s_free_inodes_count = ext2fs_swab32(sb->s_free_inodes_count);
++      sb->s_first_data_block = ext2fs_swab32(sb->s_first_data_block);
++      sb->s_log_block_size = ext2fs_swab32(sb->s_log_block_size);
++      sb->s_log_frag_size = ext2fs_swab32(sb->s_log_frag_size);
++      sb->s_blocks_per_group = ext2fs_swab32(sb->s_blocks_per_group);
++      sb->s_frags_per_group = ext2fs_swab32(sb->s_frags_per_group);
++      sb->s_inodes_per_group = ext2fs_swab32(sb->s_inodes_per_group);
++      sb->s_mtime = ext2fs_swab32(sb->s_mtime);
++      sb->s_wtime = ext2fs_swab32(sb->s_wtime);
++      sb->s_mnt_count = ext2fs_swab16(sb->s_mnt_count);
++      sb->s_max_mnt_count = ext2fs_swab16(sb->s_max_mnt_count);
++      sb->s_magic = ext2fs_swab16(sb->s_magic);
++      sb->s_state = ext2fs_swab16(sb->s_state);
++      sb->s_errors = ext2fs_swab16(sb->s_errors);
++      sb->s_minor_rev_level = ext2fs_swab16(sb->s_minor_rev_level);
++      sb->s_lastcheck = ext2fs_swab32(sb->s_lastcheck);
++      sb->s_checkinterval = ext2fs_swab32(sb->s_checkinterval);
++      sb->s_creator_os = ext2fs_swab32(sb->s_creator_os);
++      sb->s_rev_level = ext2fs_swab32(sb->s_rev_level);
++      sb->s_def_resuid = ext2fs_swab16(sb->s_def_resuid);
++      sb->s_def_resgid = ext2fs_swab16(sb->s_def_resgid);
++      sb->s_first_ino = ext2fs_swab32(sb->s_first_ino);
++      sb->s_inode_size = ext2fs_swab16(sb->s_inode_size);
++      sb->s_block_group_nr = ext2fs_swab16(sb->s_block_group_nr);
++      sb->s_feature_compat = ext2fs_swab32(sb->s_feature_compat);
++      sb->s_feature_incompat = ext2fs_swab32(sb->s_feature_incompat);
++      sb->s_feature_ro_compat = ext2fs_swab32(sb->s_feature_ro_compat);
++      sb->s_algorithm_usage_bitmap = ext2fs_swab32(sb->s_algorithm_usage_bitmap);
++      sb->s_reserved_gdt_blocks = ext2fs_swab16(sb->s_reserved_gdt_blocks);
++      sb->s_journal_inum = ext2fs_swab32(sb->s_journal_inum);
++      sb->s_journal_dev = ext2fs_swab32(sb->s_journal_dev);
++      sb->s_last_orphan = ext2fs_swab32(sb->s_last_orphan);
++      sb->s_default_mount_opts = ext2fs_swab32(sb->s_default_mount_opts);
++      sb->s_first_meta_bg = ext2fs_swab32(sb->s_first_meta_bg);
++      sb->s_mkfs_time = ext2fs_swab32(sb->s_mkfs_time);
++      for (i=0; i < 4; i++)
++              sb->s_hash_seed[i] = ext2fs_swab32(sb->s_hash_seed[i]);
++      for (i=0; i < 17; i++)
++              sb->s_jnl_blocks[i] = ext2fs_swab32(sb->s_jnl_blocks[i]);
++
++}
++
++void ext2fs_swap_group_desc(struct ext2_group_desc *gdp)
++{
++      gdp->bg_block_bitmap = ext2fs_swab32(gdp->bg_block_bitmap);
++      gdp->bg_inode_bitmap = ext2fs_swab32(gdp->bg_inode_bitmap);
++      gdp->bg_inode_table = ext2fs_swab32(gdp->bg_inode_table);
++      gdp->bg_free_blocks_count = ext2fs_swab16(gdp->bg_free_blocks_count);
++      gdp->bg_free_inodes_count = ext2fs_swab16(gdp->bg_free_inodes_count);
++      gdp->bg_used_dirs_count = ext2fs_swab16(gdp->bg_used_dirs_count);
++}
++
++void ext2fs_swap_ext_attr(char *to, char *from, int bufsize, int has_header)
++{
++      struct ext2_ext_attr_header *from_header =
++              (struct ext2_ext_attr_header *)from;
++      struct ext2_ext_attr_header *to_header =
++              (struct ext2_ext_attr_header *)to;
++      struct ext2_ext_attr_entry *from_entry, *to_entry;
++      char *from_end = (char *)from_header + bufsize;
++      int n;
++
++      if (to_header != from_header)
++              memcpy(to_header, from_header, bufsize);
++
++      from_entry = (struct ext2_ext_attr_entry *)from_header;
++      to_entry   = (struct ext2_ext_attr_entry *)to_header;
++
++      if (has_header) {
++              to_header->h_magic    = ext2fs_swab32(from_header->h_magic);
++              to_header->h_blocks   = ext2fs_swab32(from_header->h_blocks);
++              to_header->h_refcount = ext2fs_swab32(from_header->h_refcount);
++              for (n=0; n<4; n++)
++                      to_header->h_reserved[n] =
++                              ext2fs_swab32(from_header->h_reserved[n]);
++              from_entry = (struct ext2_ext_attr_entry *)(from_header+1);
++              to_entry   = (struct ext2_ext_attr_entry *)(to_header+1);
++      }
++
++      while ((char *)from_entry < from_end && *(__u32 *)from_entry) {
++              to_entry->e_value_offs  =       
++                      ext2fs_swab16(from_entry->e_value_offs);
++              to_entry->e_value_block =       
++                      ext2fs_swab32(from_entry->e_value_block);
++              to_entry->e_value_size  =       
++                      ext2fs_swab32(from_entry->e_value_size);
++              from_entry = EXT2_EXT_ATTR_NEXT(from_entry);
++              to_entry   = EXT2_EXT_ATTR_NEXT(to_entry);
++      }
++}
++
++void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t,
++                          struct ext2_inode_large *f, int hostorder,
++                          int bufsize)
++{
++      unsigned i;
++      int islnk = 0;
++      __u32 *eaf, *eat;
++
++      if (hostorder && LINUX_S_ISLNK(f->i_mode))
++              islnk = 1;
++      t->i_mode = ext2fs_swab16(f->i_mode);
++      if (!hostorder && LINUX_S_ISLNK(t->i_mode))
++              islnk = 1;
++      t->i_uid = ext2fs_swab16(f->i_uid);
++      t->i_size = ext2fs_swab32(f->i_size);
++      t->i_atime = ext2fs_swab32(f->i_atime);
++      t->i_ctime = ext2fs_swab32(f->i_ctime);
++      t->i_mtime = ext2fs_swab32(f->i_mtime);
++      t->i_dtime = ext2fs_swab32(f->i_dtime);
++      t->i_gid = ext2fs_swab16(f->i_gid);
++      t->i_links_count = ext2fs_swab16(f->i_links_count);
++      t->i_blocks = ext2fs_swab32(f->i_blocks);
++      t->i_flags = ext2fs_swab32(f->i_flags);
++      t->i_file_acl = ext2fs_swab32(f->i_file_acl);
++      t->i_dir_acl = ext2fs_swab32(f->i_dir_acl);
++      if (!islnk || ext2fs_inode_data_blocks(fs, (struct ext2_inode *)t)) {
++              for (i = 0; i < EXT2_N_BLOCKS; i++)
++                      t->i_block[i] = ext2fs_swab32(f->i_block[i]);
++      } else if (t != f) {
++              for (i = 0; i < EXT2_N_BLOCKS; i++)
++                      t->i_block[i] = f->i_block[i];
++      }
++      t->i_generation = ext2fs_swab32(f->i_generation);
++      t->i_faddr = ext2fs_swab32(f->i_faddr);
++
++      switch (fs->super->s_creator_os) {
++      case EXT2_OS_LINUX:
++              t->osd1.linux1.l_i_reserved1 =
++                      ext2fs_swab32(f->osd1.linux1.l_i_reserved1);
++              t->osd2.linux2.l_i_frag = f->osd2.linux2.l_i_frag;
++              t->osd2.linux2.l_i_fsize = f->osd2.linux2.l_i_fsize;
++              t->osd2.linux2.i_pad1 = ext2fs_swab16(f->osd2.linux2.i_pad1);
++              t->osd2.linux2.l_i_uid_high =
++                ext2fs_swab16 (f->osd2.linux2.l_i_uid_high);
++              t->osd2.linux2.l_i_gid_high =
++                ext2fs_swab16 (f->osd2.linux2.l_i_gid_high);
++              t->osd2.linux2.l_i_reserved2 =
++                      ext2fs_swab32(f->osd2.linux2.l_i_reserved2);
++              break;
++      case EXT2_OS_HURD:
++              t->osd1.hurd1.h_i_translator =
++                ext2fs_swab32 (f->osd1.hurd1.h_i_translator);
++              t->osd2.hurd2.h_i_frag = f->osd2.hurd2.h_i_frag;
++              t->osd2.hurd2.h_i_fsize = f->osd2.hurd2.h_i_fsize;
++              t->osd2.hurd2.h_i_mode_high =
++                ext2fs_swab16 (f->osd2.hurd2.h_i_mode_high);
++              t->osd2.hurd2.h_i_uid_high =
++                ext2fs_swab16 (f->osd2.hurd2.h_i_uid_high);
++              t->osd2.hurd2.h_i_gid_high =
++                ext2fs_swab16 (f->osd2.hurd2.h_i_gid_high);
++              t->osd2.hurd2.h_i_author =
++                ext2fs_swab32 (f->osd2.hurd2.h_i_author);
++              break;
++      case EXT2_OS_MASIX:
++              t->osd1.masix1.m_i_reserved1 =
++                      ext2fs_swab32(f->osd1.masix1.m_i_reserved1);
++              t->osd2.masix2.m_i_frag = f->osd2.masix2.m_i_frag;
++              t->osd2.masix2.m_i_fsize = f->osd2.masix2.m_i_fsize;
++              t->osd2.masix2.m_pad1 = ext2fs_swab16(f->osd2.masix2.m_pad1);
++              t->osd2.masix2.m_i_reserved2[0] =
++                      ext2fs_swab32(f->osd2.masix2.m_i_reserved2[0]);
++              t->osd2.masix2.m_i_reserved2[1] =
++                      ext2fs_swab32(f->osd2.masix2.m_i_reserved2[1]);
++              break;
++      }
++
++      if (bufsize < (int) (sizeof(struct ext2_inode) + sizeof(__u16)))
++              return; /* no i_extra_isize field */
++
++      t->i_extra_isize = ext2fs_swab16(f->i_extra_isize);
++      if (t->i_extra_isize > EXT2_INODE_SIZE(fs->super) -
++                              sizeof(struct ext2_inode)) {
++              /* this is error case: i_extra_size is too large */
++              return;
++      }
++
++      i = sizeof(struct ext2_inode) + t->i_extra_isize + sizeof(__u32);
++      if (bufsize < (int) i)
++              return; /* no space for EA magic */
++
++      eaf = (__u32 *) (((char *) f) + sizeof(struct ext2_inode) +
++                                      f->i_extra_isize);
++
++      if (ext2fs_swab32(*eaf) != EXT2_EXT_ATTR_MAGIC)
++              return; /* it seems no magic here */
++
++      eat = (__u32 *) (((char *) t) + sizeof(struct ext2_inode) +
++                                      f->i_extra_isize);
++      *eat = ext2fs_swab32(*eaf);
++
++      /* convert EA(s) */
++      ext2fs_swap_ext_attr((char *) (eat + 1), (char *) (eaf + 1),
++                           bufsize - sizeof(struct ext2_inode) -
++                           t->i_extra_isize - sizeof(__u32), 0);
++
++}
++
++void ext2fs_swap_inode(ext2_filsys fs, struct ext2_inode *t,
++                     struct ext2_inode *f, int hostorder)
++{
++      ext2fs_swap_inode_full(fs, (struct ext2_inode_large *) t,
++                              (struct ext2_inode_large *) f, hostorder,
++                              sizeof(struct ext2_inode));
++}
++
++#endif
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/test_io.c busybox/e2fsprogs/ext2fs/test_io.c
+--- busybox-1.00/e2fsprogs/ext2fs/test_io.c    1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/test_io.c 2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,382 @@
++/*
++ * test_io.c --- This is the Test I/O interface.
++ *
++ * Copyright (C) 1996 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <fcntl.h>
++#include <time.h>
++#if HAVE_SYS_STAT_H
++#include <sys/stat.h>
++#endif
++#if HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++/*
++ * For checking structure magic numbers...
++ */
++
++#define EXT2_CHECK_MAGIC(struct, code) \
++        if ((struct)->magic != (code)) return (code)
++  
++struct test_private_data {
++      int     magic;
++      io_channel real;
++      int flags;
++      FILE *outfile;
++      unsigned long block;
++      int read_abort_count, write_abort_count;
++      void (*read_blk)(unsigned long block, int count, errcode_t err);
++      void (*write_blk)(unsigned long block, int count, errcode_t err);
++      void (*set_blksize)(int blksize, errcode_t err);
++      void (*write_byte)(unsigned long block, int count, errcode_t err);
++};
++
++static errcode_t test_open(const char *name, int flags, io_channel *channel);
++static errcode_t test_close(io_channel channel);
++static errcode_t test_set_blksize(io_channel channel, int blksize);
++static errcode_t test_read_blk(io_channel channel, unsigned long block,
++                             int count, void *data);
++static errcode_t test_write_blk(io_channel channel, unsigned long block,
++                              int count, const void *data);
++static errcode_t test_flush(io_channel channel);
++static errcode_t test_write_byte(io_channel channel, unsigned long offset,
++                               int count, const void *buf);
++static errcode_t test_set_option(io_channel channel, const char *option, 
++                               const char *arg);
++
++static struct struct_io_manager struct_test_manager = {
++      EXT2_ET_MAGIC_IO_MANAGER,
++      "Test I/O Manager",
++      test_open,
++      test_close,
++      test_set_blksize,
++      test_read_blk,
++      test_write_blk,
++      test_flush,
++      test_write_byte,
++      test_set_option
++};
++
++io_manager test_io_manager = &struct_test_manager;
++
++/*
++ * These global variable can be set by the test program as
++ * necessary *before* calling test_open
++ */
++io_manager test_io_backing_manager = 0;
++void (*test_io_cb_read_blk)
++      (unsigned long block, int count, errcode_t err) = 0;
++void (*test_io_cb_write_blk)
++      (unsigned long block, int count, errcode_t err) = 0;
++void (*test_io_cb_set_blksize)
++      (int blksize, errcode_t err) = 0;
++void (*test_io_cb_write_byte)
++      (unsigned long block, int count, errcode_t err) = 0;
++
++/*
++ * Test flags
++ */
++#define TEST_FLAG_READ                        0x01
++#define TEST_FLAG_WRITE                       0x02
++#define TEST_FLAG_SET_BLKSIZE         0x04
++#define TEST_FLAG_FLUSH                       0x08
++#define TEST_FLAG_DUMP                        0x10
++#define TEST_FLAG_SET_OPTION          0x20
++
++static void test_dump_block(io_channel channel,
++                          struct test_private_data *data,
++                          unsigned long block, const void *buf)
++{
++      const unsigned char *cp;
++      FILE *f = data->outfile;
++      int     i;
++      unsigned long   cksum = 0;
++
++      for (i=0, cp = buf; i < channel->block_size; i++, cp++) {
++              cksum += *cp;
++      }
++      fprintf(f, "Contents of block %lu, checksum %08lu: \n", block, cksum);
++      for (i=0, cp = buf; i < channel->block_size; i++, cp++) {
++              if ((i % 16) == 0)
++                      fprintf(f, "%04x: ", i);
++              fprintf(f, "%02x%c", *cp, ((i % 16) == 15) ? '\n' : ' ');
++      }
++}
++
++static void test_abort(io_channel channel, unsigned long block)
++{
++      struct test_private_data *data;
++      FILE *f;
++
++      data = (struct test_private_data *) channel->private_data;
++      f = data->outfile;
++      test_flush(channel);
++
++      fprintf(f, "Aborting due to I/O to block %lu\n", block);
++      fflush(f);
++      abort();
++}
++
++static errcode_t test_open(const char *name, int flags, io_channel *channel)
++{
++      io_channel      io = NULL;
++      struct test_private_data *data = NULL;
++      errcode_t       retval;
++      char            *value;
++
++      if (name == 0)
++              return EXT2_ET_BAD_DEVICE_NAME;
++      retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
++      if (retval)
++              return retval;
++      memset(io, 0, sizeof(struct struct_io_channel));
++      io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
++      retval = ext2fs_get_mem(sizeof(struct test_private_data), &data);
++      if (retval) {
++              retval = EXT2_ET_NO_MEMORY;
++              goto cleanup;
++      }
++      io->manager = test_io_manager;
++      retval = ext2fs_get_mem(strlen(name)+1, &io->name);
++      if (retval)
++              goto cleanup;
++
++      strcpy(io->name, name);
++      io->private_data = data;
++      io->block_size = 1024;
++      io->read_error = 0;
++      io->write_error = 0;
++      io->refcount = 1;
++
++      memset(data, 0, sizeof(struct test_private_data));
++      data->magic = EXT2_ET_MAGIC_TEST_IO_CHANNEL;
++      if (test_io_backing_manager) {
++              retval = test_io_backing_manager->open(name, flags,
++                                                     &data->real);
++              if (retval)
++                      goto cleanup;
++      } else
++              data->real = 0;
++      data->read_blk =        test_io_cb_read_blk;
++      data->write_blk =       test_io_cb_write_blk;
++      data->set_blksize =     test_io_cb_set_blksize;
++      data->write_byte =      test_io_cb_write_byte;
++
++      data->outfile = NULL;
++      if ((value = getenv("TEST_IO_LOGFILE")) != NULL)
++              data->outfile = fopen(value, "w");
++      if (!data->outfile)
++              data->outfile = stderr;
++
++      data->flags = 0;
++      if ((value = getenv("TEST_IO_FLAGS")) != NULL)
++              data->flags = strtoul(value, NULL, 0);
++      
++      data->block = 0;
++      if ((value = getenv("TEST_IO_BLOCK")) != NULL)
++              data->block = strtoul(value, NULL, 0);
++
++      data->read_abort_count = 0;
++      if ((value = getenv("TEST_IO_READ_ABORT")) != NULL)
++              data->read_abort_count = strtoul(value, NULL, 0);
++
++      data->write_abort_count = 0;
++      if ((value = getenv("TEST_IO_WRITE_ABORT")) != NULL)
++              data->write_abort_count = strtoul(value, NULL, 0);
++      
++      *channel = io;
++      return 0;
++
++cleanup:
++      if (io)
++              ext2fs_free_mem(&io);
++      if (data)
++              ext2fs_free_mem(&data);
++      return retval;
++}
++
++static errcode_t test_close(io_channel channel)
++{
++      struct test_private_data *data;
++      errcode_t       retval = 0;
++
++      EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
++      data = (struct test_private_data *) channel->private_data;
++      EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
++
++      if (--channel->refcount > 0)
++              return 0;
++      
++      if (data->real)
++              retval = io_channel_close(data->real);
++
++      if (data->outfile && data->outfile != stderr)
++              fclose(data->outfile);
++      
++      ext2fs_free_mem(&channel->private_data);
++      if (channel->name)
++              ext2fs_free_mem(&channel->name);
++      ext2fs_free_mem(&channel);
++      return retval;
++}
++
++static errcode_t test_set_blksize(io_channel channel, int blksize)
++{
++      struct test_private_data *data;
++      errcode_t       retval = 0;
++
++      EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
++      data = (struct test_private_data *) channel->private_data;
++      EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
++
++      if (data->real)
++              retval = io_channel_set_blksize(data->real, blksize);
++      if (data->set_blksize)
++              data->set_blksize(blksize, retval);
++      if (data->flags & TEST_FLAG_SET_BLKSIZE)
++              fprintf(data->outfile,
++                      "Test_io: set_blksize(%d) returned %s\n",
++                      blksize, retval ? error_message(retval) : "OK");
++      channel->block_size = blksize;
++      return retval;
++}
++
++
++static errcode_t test_read_blk(io_channel channel, unsigned long block,
++                             int count, void *buf)
++{
++      struct test_private_data *data;
++      errcode_t       retval = 0;
++
++      EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
++      data = (struct test_private_data *) channel->private_data;
++      EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
++
++      if (data->real)
++              retval = io_channel_read_blk(data->real, block, count, buf);
++      if (data->read_blk)
++              data->read_blk(block, count, retval);
++      if (data->flags & TEST_FLAG_READ)
++              fprintf(data->outfile,
++                      "Test_io: read_blk(%lu, %d) returned %s\n",
++                      block, count, retval ? error_message(retval) : "OK");
++      if (data->block && data->block == block) {
++              if (data->flags & TEST_FLAG_DUMP)
++                      test_dump_block(channel, data, block, buf);
++              if (--data->read_abort_count == 0)
++                      test_abort(channel, block);
++      } 
++      return retval;
++}
++
++static errcode_t test_write_blk(io_channel channel, unsigned long block,
++                             int count, const void *buf)
++{
++      struct test_private_data *data;
++      errcode_t       retval = 0;
++
++      EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
++      data = (struct test_private_data *) channel->private_data;
++      EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
++
++      if (data->real)
++              retval = io_channel_write_blk(data->real, block, count, buf);
++      if (data->write_blk)
++              data->write_blk(block, count, retval);
++      if (data->flags & TEST_FLAG_WRITE)
++              fprintf(data->outfile,
++                      "Test_io: write_blk(%lu, %d) returned %s\n",
++                      block, count, retval ? error_message(retval) : "OK");
++      if (data->block && data->block == block) {
++              if (data->flags & TEST_FLAG_DUMP)
++                      test_dump_block(channel, data, block, buf);
++              if (--data->write_abort_count == 0)
++                      test_abort(channel, block);
++      }
++      return retval;
++}
++
++static errcode_t test_write_byte(io_channel channel, unsigned long offset,
++                             int count, const void *buf)
++{
++      struct test_private_data *data;
++      errcode_t       retval = 0;
++
++      EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
++      data = (struct test_private_data *) channel->private_data;
++      EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
++
++      if (data->real && data->real->manager->write_byte)
++              retval = io_channel_write_byte(data->real, offset, count, buf);
++      if (data->write_byte)
++              data->write_byte(offset, count, retval);
++      if (data->flags & TEST_FLAG_WRITE)
++              fprintf(data->outfile,
++                      "Test_io: write_byte(%lu, %d) returned %s\n",
++                      offset, count, retval ? error_message(retval) : "OK");
++      return retval;
++}
++
++/*
++ * Flush data buffers to disk.
++ */
++static errcode_t test_flush(io_channel channel)
++{
++      struct test_private_data *data;
++      errcode_t       retval = 0;
++      
++      EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
++      data = (struct test_private_data *) channel->private_data;
++      EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
++
++      if (data->real)
++              retval = io_channel_flush(data->real);
++      
++      if (data->flags & TEST_FLAG_FLUSH)
++              fprintf(data->outfile, "Test_io: flush() returned %s\n",
++                      retval ? error_message(retval) : "OK");
++      
++      return retval;
++}
++
++static errcode_t test_set_option(io_channel channel, const char *option, 
++                               const char *arg)
++{
++      struct test_private_data *data;
++      errcode_t       retval = 0;
++
++      EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
++      data = (struct test_private_data *) channel->private_data;
++      EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
++
++
++      if (data->flags & TEST_FLAG_SET_OPTION)
++              fprintf(data->outfile, "Test_io: set_option(%s, %s) ", 
++                      option, arg);
++      if (data->real && data->real->manager->set_option) {
++              retval = (data->real->manager->set_option)(data->real, 
++                                                         option, arg);
++              if (data->flags & TEST_FLAG_SET_OPTION)
++                      fprintf(data->outfile, "returned %s\n",
++                              retval ? error_message(retval) : "OK");
++      } else {
++              if (data->flags & TEST_FLAG_SET_OPTION)
++                      fprintf(data->outfile, "not implemented\n");
++      }
++      return retval;
++}
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/unix_io.c busybox/e2fsprogs/ext2fs/unix_io.c
+--- busybox-1.00/e2fsprogs/ext2fs/unix_io.c    1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/unix_io.c 2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,707 @@
++/*
++ * unix_io.c --- This is the Unix (well, really POSIX) implementation
++ *    of the I/O manager.
++ *
++ * Implements a one-block write-through cache.
++ *
++ * Includes support for Windows NT support under Cygwin. 
++ *
++ * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
++ *    2002 by Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#if HAVE_ERRNO_H
++#include <errno.h>
++#endif
++#include <fcntl.h>
++#include <time.h>
++#ifdef __linux__
++#include <sys/utsname.h>
++#endif
++#if HAVE_SYS_STAT_H
++#include <sys/stat.h>
++#endif
++#if HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++#if HAVE_SYS_RESOURCE_H
++#include <sys/resource.h>
++#endif
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++/*
++ * For checking structure magic numbers...
++ */
++
++#define EXT2_CHECK_MAGIC(struct, code) \
++        if ((struct)->magic != (code)) return (code)
++
++struct unix_cache {
++      char            *buf;
++      unsigned long   block;
++      int             access_time;
++      unsigned        dirty:1;
++      unsigned        in_use:1;
++};
++
++#define CACHE_SIZE 8
++#define WRITE_DIRECT_SIZE 4   /* Must be smaller than CACHE_SIZE */
++#define READ_DIRECT_SIZE 4    /* Should be smaller than CACHE_SIZE */
++
++struct unix_private_data {
++      int     magic;
++      int     dev;
++      int     flags;
++      int     access_time;
++      ext2_loff_t offset;
++      struct unix_cache cache[CACHE_SIZE];
++};
++
++static errcode_t unix_open(const char *name, int flags, io_channel *channel);
++static errcode_t unix_close(io_channel channel);
++static errcode_t unix_set_blksize(io_channel channel, int blksize);
++static errcode_t unix_read_blk(io_channel channel, unsigned long block,
++                             int count, void *data);
++static errcode_t unix_write_blk(io_channel channel, unsigned long block,
++                              int count, const void *data);
++static errcode_t unix_flush(io_channel channel);
++static errcode_t unix_write_byte(io_channel channel, unsigned long offset,
++                              int size, const void *data);
++static errcode_t unix_set_option(io_channel channel, const char *option, 
++                               const char *arg);
++
++static void reuse_cache(io_channel channel, struct unix_private_data *data,
++               struct unix_cache *cache, unsigned long block);
++
++/* __FreeBSD_kernel__ is defined by GNU/kFreeBSD - the FreeBSD kernel
++ * does not know buffered block devices - everything is raw. */
++#if defined(__CYGWIN__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
++#define NEED_BOUNCE_BUFFER
++#else
++#undef NEED_BOUNCE_BUFFER
++#endif
++
++static struct struct_io_manager struct_unix_manager = {
++      EXT2_ET_MAGIC_IO_MANAGER,
++      "Unix I/O Manager",
++      unix_open,
++      unix_close,
++      unix_set_blksize,
++      unix_read_blk,
++      unix_write_blk,
++      unix_flush,
++#ifdef NEED_BOUNCE_BUFFER
++      0,
++#else
++      unix_write_byte,
++#endif
++      unix_set_option
++};
++
++io_manager unix_io_manager = &struct_unix_manager;
++
++/*
++ * Here are the raw I/O functions
++ */
++#ifndef NEED_BOUNCE_BUFFER
++static errcode_t raw_read_blk(io_channel channel,
++                            struct unix_private_data *data,
++                            unsigned long block,
++                            int count, void *buf)
++{
++      errcode_t       retval;
++      ssize_t         size;
++      ext2_loff_t     location;
++      int             actual = 0;
++
++      size = (count < 0) ? -count : count * channel->block_size;
++      location = ((ext2_loff_t) block * channel->block_size) + data->offset;
++      if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
++              retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
++              goto error_out;
++      }
++      actual = read(data->dev, buf, size);
++      if (actual != size) {
++              if (actual < 0)
++                      actual = 0;
++              retval = EXT2_ET_SHORT_READ;
++              goto error_out;
++      }
++      return 0;
++      
++error_out:
++      memset((char *) buf+actual, 0, size-actual);
++      if (channel->read_error)
++              retval = (channel->read_error)(channel, block, count, buf,
++                                             size, actual, retval);
++      return retval;
++}
++#else /* NEED_BOUNCE_BUFFER */
++/*
++ * Windows and FreeBSD block devices only allow sector alignment IO in offset and size
++ */
++static errcode_t raw_read_blk(io_channel channel,
++                            struct unix_private_data *data,
++                            unsigned long block,
++                            int count, void *buf)
++{
++      errcode_t       retval;
++      size_t          size, alignsize, fragment;
++      ext2_loff_t     location;
++      int             total = 0, actual;
++#define BLOCKALIGN 512
++      char            sector[BLOCKALIGN];
++
++      size = (count < 0) ? -count : count * channel->block_size;
++      location = ((ext2_loff_t) block * channel->block_size) + data->offset;
++#ifdef DEBUG
++      printf("count=%d, size=%d, block=%d, blk_size=%d, location=%lx\n",
++                      count, size, block, channel->block_size, location);
++#endif
++      if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
++              retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
++              goto error_out;
++      }
++      fragment = size % BLOCKALIGN;
++      alignsize = size - fragment;
++      if (alignsize) {
++              actual = read(data->dev, buf, alignsize);
++              if (actual != alignsize)
++                      goto short_read;
++      }
++      if (fragment) {
++              actual = read(data->dev, sector, BLOCKALIGN);
++              if (actual != BLOCKALIGN)
++                      goto short_read;
++              memcpy(buf+alignsize, sector, fragment);
++      }
++      return 0;
++
++short_read:
++      if (actual>0)
++              total += actual;
++      retval = EXT2_ET_SHORT_READ;
++
++error_out:
++      memset((char *) buf+total, 0, size-actual);
++      if (channel->read_error)
++              retval = (channel->read_error)(channel, block, count, buf,
++                                             size, actual, retval);
++      return retval;
++}
++#endif
++
++static errcode_t raw_write_blk(io_channel channel,
++                             struct unix_private_data *data,
++                             unsigned long block,
++                             int count, const void *buf)
++{
++      ssize_t         size;
++      ext2_loff_t     location;
++      int             actual = 0;
++      errcode_t       retval;
++
++      if (count == 1)
++              size = channel->block_size;
++      else {
++              if (count < 0)
++                      size = -count;
++              else
++                      size = count * channel->block_size;
++      }
++
++      location = ((ext2_loff_t) block * channel->block_size) + data->offset;
++      if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
++              retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
++              goto error_out;
++      }
++      
++      actual = write(data->dev, buf, size);
++      if (actual != size) {
++              retval = EXT2_ET_SHORT_WRITE;
++              goto error_out;
++      }
++      return 0;
++      
++error_out:
++      if (channel->write_error)
++              retval = (channel->write_error)(channel, block, count, buf,
++                                              size, actual, retval);
++      return retval;
++}
++
++
++/*
++ * Here we implement the cache functions
++ */
++
++/* Allocate the cache buffers */
++static errcode_t alloc_cache(io_channel channel,
++                           struct unix_private_data *data)
++{
++      errcode_t               retval;
++      struct unix_cache       *cache;
++      int                     i;
++      
++      data->access_time = 0;
++      for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
++              cache->block = 0;
++              cache->access_time = 0;
++              cache->dirty = 0;
++              cache->in_use = 0;
++              if ((retval = ext2fs_get_mem(channel->block_size,
++                                           &cache->buf)))
++                      return retval;
++      }
++      return 0;
++}
++
++/* Free the cache buffers */
++static void free_cache(struct unix_private_data *data)
++{
++      struct unix_cache       *cache;
++      int                     i;
++      
++      data->access_time = 0;
++      for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
++              cache->block = 0;
++              cache->access_time = 0;
++              cache->dirty = 0;
++              cache->in_use = 0;
++              if (cache->buf)
++                      ext2fs_free_mem(&cache->buf);
++              cache->buf = 0;
++      }
++}
++
++#ifndef NO_IO_CACHE
++/*
++ * Try to find a block in the cache.  If the block is not found, and
++ * eldest is a non-zero pointer, then fill in eldest with the cache
++ * entry to that should be reused.
++ */
++static struct unix_cache *find_cached_block(struct unix_private_data *data,
++                                          unsigned long block,
++                                          struct unix_cache **eldest)
++{
++      struct unix_cache       *cache, *unused_cache, *oldest_cache;
++      int                     i;
++      
++      unused_cache = oldest_cache = 0;
++      for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
++              if (!cache->in_use) {
++                      if (!unused_cache)
++                              unused_cache = cache;
++                      continue;
++              }
++              if (cache->block == block) {
++                      cache->access_time = ++data->access_time;
++                      return cache;
++              }
++              if (!oldest_cache ||
++                  (cache->access_time < oldest_cache->access_time))
++                      oldest_cache = cache;
++      }
++      if (eldest)
++              *eldest = (unused_cache) ? unused_cache : oldest_cache;
++      return 0;
++}
++
++/*
++ * Reuse a particular cache entry for another block.
++ */
++static void reuse_cache(io_channel channel, struct unix_private_data *data,
++               struct unix_cache *cache, unsigned long block)
++{
++      if (cache->dirty && cache->in_use)
++              raw_write_blk(channel, data, cache->block, 1, cache->buf);
++
++      cache->in_use = 1;
++      cache->dirty = 0;
++      cache->block = block;
++      cache->access_time = ++data->access_time;
++}
++
++/*
++ * Flush all of the blocks in the cache
++ */
++static errcode_t flush_cached_blocks(io_channel channel,
++                                   struct unix_private_data *data,
++                                   int invalidate)
++
++{
++      struct unix_cache       *cache;
++      errcode_t               retval, retval2;
++      int                     i;
++      
++      retval2 = 0;
++      for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
++              if (!cache->in_use)
++                      continue;
++              
++              if (invalidate)
++                      cache->in_use = 0;
++              
++              if (!cache->dirty)
++                      continue;
++              
++              retval = raw_write_blk(channel, data,
++                                     cache->block, 1, cache->buf);
++              if (retval)
++                      retval2 = retval;
++              else
++                      cache->dirty = 0;
++      }
++      return retval2;
++}
++#endif /* NO_IO_CACHE */
++
++static errcode_t unix_open(const char *name, int flags, io_channel *channel)
++{
++      io_channel      io = NULL;
++      struct unix_private_data *data = NULL;
++      errcode_t       retval;
++      int             open_flags;
++      struct stat     st;
++#ifdef __linux__
++      struct          utsname ut;
++#endif
++
++      if (name == 0)
++              return EXT2_ET_BAD_DEVICE_NAME;
++      retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
++      if (retval)
++              return retval;
++      memset(io, 0, sizeof(struct struct_io_channel));
++      io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
++      retval = ext2fs_get_mem(sizeof(struct unix_private_data), &data);
++      if (retval)
++              goto cleanup;
++
++      io->manager = unix_io_manager;
++      retval = ext2fs_get_mem(strlen(name)+1, &io->name);
++      if (retval)
++              goto cleanup;
++
++      strcpy(io->name, name);
++      io->private_data = data;
++      io->block_size = 1024;
++      io->read_error = 0;
++      io->write_error = 0;
++      io->refcount = 1;
++
++      memset(data, 0, sizeof(struct unix_private_data));
++      data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL;
++
++      if ((retval = alloc_cache(io, data)))
++              goto cleanup;
++
++      open_flags = (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY;
++#ifdef CONFIG_LFS
++      data->dev = open64(io->name, open_flags);
++#else
++      data->dev = open(io->name, open_flags);
++#endif
++      if (data->dev < 0) {
++              retval = errno;
++              goto cleanup;
++      }
++
++#ifdef __linux__
++#undef RLIM_INFINITY
++#if (defined(__alpha__) || ((defined(__sparc__) || defined(__mips__)) && (SIZEOF_LONG == 4)))
++#define RLIM_INFINITY ((unsigned long)(~0UL>>1))
++#else
++#define RLIM_INFINITY  (~0UL)
++#endif
++      /*
++       * Work around a bug in 2.4.10-2.4.18 kernels where writes to
++       * block devices are wrongly getting hit by the filesize
++       * limit.  This workaround isn't perfect, since it won't work
++       * if glibc wasn't built against 2.2 header files.  (Sigh.)
++       * 
++       */
++      if ((flags & IO_FLAG_RW) &&
++          (uname(&ut) == 0) &&
++          ((ut.release[0] == '2') && (ut.release[1] == '.') &&
++           (ut.release[2] == '4') && (ut.release[3] == '.') &&
++           (ut.release[4] == '1') && (ut.release[5] >= '0') &&
++           (ut.release[5] < '8')) &&
++          (fstat(data->dev, &st) == 0) &&
++          (S_ISBLK(st.st_mode))) {
++              struct rlimit   rlim;
++              
++              rlim.rlim_cur = rlim.rlim_max = (unsigned long) RLIM_INFINITY;
++              setrlimit(RLIMIT_FSIZE, &rlim);
++              getrlimit(RLIMIT_FSIZE, &rlim);
++              if (((unsigned long) rlim.rlim_cur) <
++                  ((unsigned long) rlim.rlim_max)) {
++                      rlim.rlim_cur = rlim.rlim_max;
++                      setrlimit(RLIMIT_FSIZE, &rlim);
++              }
++      }
++#endif
++      *channel = io;
++      return 0;
++
++cleanup:
++      if (data) {
++              free_cache(data);
++              ext2fs_free_mem(&data);
++      }
++      if (io)
++              ext2fs_free_mem(&io);
++      return retval;
++}
++
++static errcode_t unix_close(io_channel channel)
++{
++      struct unix_private_data *data;
++      errcode_t       retval = 0;
++
++      EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
++      data = (struct unix_private_data *) channel->private_data;
++      EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
++
++      if (--channel->refcount > 0)
++              return 0;
++
++#ifndef NO_IO_CACHE
++      retval = flush_cached_blocks(channel, data, 0);
++#endif
++
++      if (close(data->dev) < 0)
++              retval = errno;
++      free_cache(data);
++
++      ext2fs_free_mem(&channel->private_data);
++      if (channel->name)
++              ext2fs_free_mem(&channel->name);
++      ext2fs_free_mem(&channel);
++      return retval;
++}
++
++static errcode_t unix_set_blksize(io_channel channel, int blksize)
++{
++      struct unix_private_data *data;
++      errcode_t               retval;
++
++      EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
++      data = (struct unix_private_data *) channel->private_data;
++      EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
++
++      if (channel->block_size != blksize) {
++#ifndef NO_IO_CACHE
++              if ((retval = flush_cached_blocks(channel, data, 0)))
++                      return retval;
++#endif
++              
++              channel->block_size = blksize;
++              free_cache(data);
++              if ((retval = alloc_cache(channel, data)))
++                      return retval;
++      }
++      return 0;
++}
++
++
++static errcode_t unix_read_blk(io_channel channel, unsigned long block,
++                             int count, void *buf)
++{
++      struct unix_private_data *data;
++      struct unix_cache *cache, *reuse[READ_DIRECT_SIZE];
++      errcode_t       retval;
++      char            *cp;
++      int             i, j;
++
++      EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
++      data = (struct unix_private_data *) channel->private_data;
++      EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
++
++#ifdef NO_IO_CACHE
++      return raw_read_blk(channel, data, block, count, buf);
++#else
++      /*
++       * If we're doing an odd-sized read or a very large read,
++       * flush out the cache and then do a direct read.
++       */
++      if (count < 0 || count > WRITE_DIRECT_SIZE) {
++              if ((retval = flush_cached_blocks(channel, data, 0)))
++                      return retval;
++              return raw_read_blk(channel, data, block, count, buf);
++      }
++
++      cp = buf;
++      while (count > 0) {
++              /* If it's in the cache, use it! */
++              if ((cache = find_cached_block(data, block, &reuse[0]))) {
++#ifdef DEBUG
++                      printf("Using cached block %d\n", block);
++#endif
++                      memcpy(cp, cache->buf, channel->block_size);
++                      count--;
++                      block++;
++                      cp += channel->block_size;
++                      continue;
++              }
++              /*
++               * Find the number of uncached blocks so we can do a
++               * single read request
++               */
++              for (i=1; i < count; i++)
++                      if (find_cached_block(data, block+i, &reuse[i]))
++                              break;
++#ifdef DEBUG
++              printf("Reading %d blocks starting at %d\n", i, block);
++#endif
++              if ((retval = raw_read_blk(channel, data, block, i, cp)))
++                      return retval;
++              
++              /* Save the results in the cache */
++              for (j=0; j < i; j++) {
++                      count--;
++                      cache = reuse[j];
++                      reuse_cache(channel, data, cache, block++);
++                      memcpy(cache->buf, cp, channel->block_size);
++                      cp += channel->block_size;
++              }
++      }
++      return 0;
++#endif /* NO_IO_CACHE */
++}
++
++static errcode_t unix_write_blk(io_channel channel, unsigned long block,
++                              int count, const void *buf)
++{
++      struct unix_private_data *data;
++      struct unix_cache *cache, *reuse;
++      errcode_t       retval = 0;
++      const char      *cp;
++      int             writethrough;
++
++      EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
++      data = (struct unix_private_data *) channel->private_data;
++      EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
++
++#ifdef NO_IO_CACHE
++      return raw_write_blk(channel, data, block, count, buf);
++#else 
++      /*
++       * If we're doing an odd-sized write or a very large write,
++       * flush out the cache completely and then do a direct write.
++       */
++      if (count < 0 || count > WRITE_DIRECT_SIZE) {
++              if ((retval = flush_cached_blocks(channel, data, 1)))
++                      return retval;
++              return raw_write_blk(channel, data, block, count, buf);
++      }
++
++      /*
++       * For a moderate-sized multi-block write, first force a write
++       * if we're in write-through cache mode, and then fill the
++       * cache with the blocks.
++       */
++      writethrough = channel->flags & CHANNEL_FLAGS_WRITETHROUGH;
++      if (writethrough)
++              retval = raw_write_blk(channel, data, block, count, buf);
++      
++      cp = buf;
++      while (count > 0) {
++              cache = find_cached_block(data, block, &reuse);
++              if (!cache) {
++                      cache = reuse;
++                      reuse_cache(channel, data, cache, block);
++              }
++              memcpy(cache->buf, cp, channel->block_size);
++              cache->dirty = !writethrough;
++              count--;
++              block++;
++              cp += channel->block_size;
++      }
++      return retval;
++#endif /* NO_IO_CACHE */
++}
++
++static errcode_t unix_write_byte(io_channel channel, unsigned long offset,
++                               int size, const void *buf)
++{
++      struct unix_private_data *data;
++      errcode_t       retval = 0;
++      ssize_t         actual;
++
++      EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
++      data = (struct unix_private_data *) channel->private_data;
++      EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
++
++#ifndef NO_IO_CACHE
++      /*
++       * Flush out the cache completely
++       */
++      if ((retval = flush_cached_blocks(channel, data, 1)))
++              return retval;
++#endif
++
++      if (lseek(data->dev, offset + data->offset, SEEK_SET) < 0)
++              return errno;
++      
++      actual = write(data->dev, buf, size);
++      if (actual != size)
++              return EXT2_ET_SHORT_WRITE;
++
++      return 0;
++}
++
++/*
++ * Flush data buffers to disk.  
++ */
++static errcode_t unix_flush(io_channel channel)
++{
++      struct unix_private_data *data;
++      errcode_t retval = 0;
++      
++      EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
++      data = (struct unix_private_data *) channel->private_data;
++      EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
++
++#ifndef NO_IO_CACHE
++      retval = flush_cached_blocks(channel, data, 0);
++#endif
++      fsync(data->dev);
++      return retval;
++}
++
++static errcode_t unix_set_option(io_channel channel, const char *option, 
++                               const char *arg)
++{
++      struct unix_private_data *data;
++      unsigned long tmp;
++      char *end;
++
++      EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
++      data = (struct unix_private_data *) channel->private_data;
++      EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
++
++      if (!strcmp(option, "offset")) {
++              if (!arg)
++                      return EXT2_ET_INVALID_ARGUMENT;
++
++              tmp = strtoul(arg, &end, 0);
++              if (*end)
++                      return EXT2_ET_INVALID_ARGUMENT;
++              data->offset = tmp;
++              return 0;
++      }
++      return EXT2_ET_INVALID_ARGUMENT;
++}
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/unlink.c busybox/e2fsprogs/ext2fs/unlink.c
+--- busybox-1.00/e2fsprogs/ext2fs/unlink.c     1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/unlink.c  2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,99 @@
++/*
++ * unlink.c --- delete links in a ext2fs directory
++ * 
++ * Copyright (C) 1993, 1994, 1997 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <string.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++struct link_struct  {
++      const char      *name;
++      int             namelen;
++      ext2_ino_t      inode;
++      int             flags;
++      struct ext2_dir_entry *prev;
++      int             done;
++};    
++
++#ifdef __TURBOC__
++ #pragma argsused
++#endif
++static int unlink_proc(struct ext2_dir_entry *dirent,
++                   int        offset EXT2FS_ATTR((unused)),
++                   int        blocksize EXT2FS_ATTR((unused)),
++                   char       *buf EXT2FS_ATTR((unused)),
++                   void       *priv_data)
++{
++      struct link_struct *ls = (struct link_struct *) priv_data;
++      struct ext2_dir_entry *prev;
++
++      prev = ls->prev;
++      ls->prev = dirent;
++
++      if (ls->name) {
++              if ((dirent->name_len & 0xFF) != ls->namelen)
++                      return 0;
++              if (strncmp(ls->name, dirent->name, dirent->name_len & 0xFF))
++                      return 0;
++      }
++      if (ls->inode) {
++              if (dirent->inode != ls->inode)
++                      return 0;
++      } else {
++              if (!dirent->inode)
++                      return 0;
++      }
++
++      if (prev) 
++              prev->rec_len += dirent->rec_len;
++      else
++              dirent->inode = 0;
++      ls->done++;
++      return DIRENT_ABORT|DIRENT_CHANGED;
++}
++
++#ifdef __TURBOC__
++ #pragma argsused
++#endif
++errcode_t ext2fs_unlink(ext2_filsys fs, ext2_ino_t dir,
++                      const char *name, ext2_ino_t ino,
++                      int flags EXT2FS_ATTR((unused)))
++{
++      errcode_t       retval;
++      struct link_struct ls;
++
++      EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
++
++      if (!name && !ino)
++              return EXT2_ET_INVALID_ARGUMENT;
++
++      if (!(fs->flags & EXT2_FLAG_RW))
++              return EXT2_ET_RO_FILSYS;
++
++      ls.name = name;
++      ls.namelen = name ? strlen(name) : 0;
++      ls.inode = ino;
++      ls.flags = 0;
++      ls.done = 0;
++      ls.prev = 0;
++
++      retval = ext2fs_dir_iterate(fs, dir, DIRENT_FLAG_INCLUDE_EMPTY, 
++                                  0, unlink_proc, &ls);
++      if (retval)
++              return retval;
++
++      return (ls.done) ? 0 : EXT2_ET_DIR_NO_SPACE;
++}
++
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/valid_blk.c busybox/e2fsprogs/ext2fs/valid_blk.c
+--- busybox-1.00/e2fsprogs/ext2fs/valid_blk.c  1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/valid_blk.c       2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,56 @@
++/*
++ * valid_blk.c --- does the inode have valid blocks?
++ *
++ * Copyright 1997 by Theodore Ts'o
++ * 
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ * 
++ */
++
++#include <stdio.h>
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <string.h>
++#include <time.h>
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++/*
++ * This function returns 1 if the inode's block entries actually
++ * contain block entries.
++ */
++int ext2fs_inode_has_valid_blocks(struct ext2_inode *inode)
++{
++      /*
++       * Only directories, regular files, and some symbolic links
++       * have valid block entries.
++       */
++      if (!LINUX_S_ISDIR(inode->i_mode) && !LINUX_S_ISREG(inode->i_mode) &&
++          !LINUX_S_ISLNK(inode->i_mode))
++              return 0;
++      
++      /*
++       * If the symbolic link is a "fast symlink", then the symlink
++       * target is stored in the block entries.
++       */
++      if (LINUX_S_ISLNK (inode->i_mode)) {
++              if (inode->i_file_acl == 0) {
++                      /* With no EA block, we can rely on i_blocks */
++                      if (inode->i_blocks == 0)
++                              return 0;
++              } else {
++                      /* With an EA block, life gets more tricky */
++                      if (inode->i_size >= EXT2_N_BLOCKS*4)
++                              return 1; /* definitely using i_block[] */
++                      if (inode->i_size > 4 && inode->i_block[1] == 0)
++                              return 1; /* definitely using i_block[] */
++                      return 0; /* Probably a fast symlink */
++              }
++      }
++      return 1;
++}
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/version.c busybox/e2fsprogs/ext2fs/version.c
+--- busybox-1.00/e2fsprogs/ext2fs/version.c    1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/version.c 2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,52 @@
++/*
++ * version.c --- Return the version of the ext2 library
++ *
++ * Copyright (C) 1997 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#if HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <string.h>
++#include <stdio.h>
++#include <ctype.h>
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++//#include "../../version.h"
++
++static const char *lib_version = E2FSPROGS_VERSION;
++static const char *lib_date = E2FSPROGS_DATE;
++
++int ext2fs_parse_version_string(const char *ver_string)
++{
++      const char *cp;
++      int version = 0;
++
++      for (cp = ver_string; *cp; cp++) {
++              if (*cp == '.')
++                      continue;
++              if (!isdigit(*cp))
++                      break;
++              version = (version * 10) + (*cp - '0');
++      }
++      return version;
++}
++
++
++int ext2fs_get_library_version(const char **ver_string,
++                             const char **date_string)
++{
++      if (ver_string)
++              *ver_string = lib_version;
++      if (date_string)
++              *date_string = lib_date;
++
++      return ext2fs_parse_version_string(lib_version);
++}
+diff -Nur busybox-1.00/e2fsprogs/ext2fs/write_bb_file.c busybox/e2fsprogs/ext2fs/write_bb_file.c
+--- busybox-1.00/e2fsprogs/ext2fs/write_bb_file.c      1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/ext2fs/write_bb_file.c   2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,34 @@
++/*
++ * write_bb_file.c --- write a list of bad blocks to a FILE *
++ *
++ * Copyright (C) 1994, 1995 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++
++#include "ext2_fs.h"
++#include "ext2fs.h"
++
++errcode_t ext2fs_write_bb_FILE(ext2_badblocks_list bb_list,
++                             unsigned int flags EXT2FS_ATTR((unused)),
++                             FILE *f)
++{
++      badblocks_iterate       bb_iter;
++      blk_t                   blk;
++      errcode_t               retval;
++
++      retval = ext2fs_badblocks_list_iterate_begin(bb_list, &bb_iter);
++      if (retval)
++              return retval;
++
++      while (ext2fs_badblocks_list_iterate(bb_iter, &blk)) {
++              fprintf(f, "%d\n", blk);
++      }
++      ext2fs_badblocks_list_iterate_end(bb_iter);
++      return 0;
++}
+diff -Nur busybox-1.00/e2fsprogs/lsattr.c busybox/e2fsprogs/lsattr.c
+--- busybox-1.00/e2fsprogs/lsattr.c    1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/lsattr.c 2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,141 @@
++/*
++ * lsattr.c           - List file attributes on an ext2 file system
++ *
++ * Copyright (C) 1993, 1994  Remy Card <card@masi.ibp.fr>
++ *                           Laboratoire MASI, Institut Blaise Pascal
++ *                           Universite Pierre et Marie Curie (Paris VI)
++ *
++ * This file can be redistributed under the terms of the GNU General
++ * Public License
++ */
++
++/*
++ * History:
++ * 93/10/30   - Creation
++ * 93/11/13   - Replace stat() calls by lstat() to avoid loops
++ * 94/02/27   - Integrated in Ted's distribution
++ * 98/12/29   - Display version info only when -V specified (G M Sipe)
++ */
++
++#include <sys/types.h>
++#include <dirent.h>
++#include <errno.h>
++#include <fcntl.h>
++#include <getopt.h>
++#include <stdio.h>
++#include <unistd.h>
++#include <stdlib.h>
++#include <string.h>
++#include <sys/param.h>
++#include <sys/stat.h>
++
++#include <ext2fs/ext2_fs.h>
++#include "e2fsbb.h"
++#include "e2p/e2p.h"
++
++#ifdef __GNUC__
++# define EXT2FS_ATTR(x) __attribute__(x)
++#else
++# define EXT2FS_ATTR(x)
++#endif
++
++#define OPT_RECUR 1
++#define OPT_ALL 2
++#define OPT_DIRS_OPT 4
++#define OPT_PF_LONG 8
++#define OPT_GENERATION 16
++static int flags;
++
++#ifdef CONFIG_LFS
++# define LSTAT lstat64
++# define STRUCT_STAT struct stat64
++#else
++# define LSTAT lstat
++# define STRUCT_STAT struct stat
++#endif
++
++static void list_attributes(const char *name)
++{
++      unsigned long fsflags;
++      unsigned long generation;
++
++      if (fgetflags(name, &fsflags) == -1)
++              goto read_err;
++      if (flags & OPT_GENERATION) {
++              if (fgetversion(name, &generation) == -1)
++                      goto read_err;
++              printf("%5lu ", generation);
++      }
++
++      if (flags & OPT_PF_LONG) {
++              printf("%-28s ", name);
++              print_flags(stdout, fsflags, PFOPT_LONG);
++              printf("\n");
++      } else {
++              print_flags(stdout, fsflags, 0);
++              printf(" %s\n", name);
++      }
++
++      return;
++read_err:
++      bb_perror_msg("reading %s", name);
++}
++
++static int lsattr_dir_proc(const char *, struct dirent *, void *);
++
++static void lsattr_args(const char *name)
++{
++      STRUCT_STAT     st;
++
++      if (LSTAT(name, &st) == -1) {
++              bb_perror_msg("stating %s", name);
++      } else {
++              if (S_ISDIR(st.st_mode) && !(flags & OPT_DIRS_OPT))
++                      iterate_on_dir(name, lsattr_dir_proc, NULL);
++              else
++                      list_attributes(name);
++      }
++}
++
++static int lsattr_dir_proc(const char *dir_name, struct dirent *de, 
++                           void *private EXT2FS_ATTR((unused)))
++{
++      STRUCT_STAT     st;
++      char *path;
++
++      path = concat_path_file(dir_name, de->d_name);
++
++      if (LSTAT(path, &st) == -1)
++              bb_perror_msg(path);
++      else {
++              if (de->d_name[0] != '.' || (flags & OPT_ALL)) {
++                      list_attributes(path);
++                      if (S_ISDIR(st.st_mode) && (flags & OPT_RECUR) &&
++                         (de->d_name[0] != '.' && (de->d_name[1] != '\0' ||
++                         (de->d_name[1] != '.' && de->d_name[2] != '\0')))) {
++                              printf("\n%s:\n", path);
++                              iterate_on_dir(path, lsattr_dir_proc, NULL);
++                              printf("\n");
++                      }
++              }
++      }
++
++      free(path);
++
++      return 0;
++}
++
++int lsattr_main(int argc, char **argv)
++{
++      int i;
++
++      flags = bb_getopt_ulflags(argc, argv, "Radlv");
++
++      if (optind > argc - 1)
++              lsattr_args(".");
++      else
++              for (i = optind; i < argc; i++)
++                      lsattr_args(argv[i]);
++
++      return EXIT_SUCCESS;
++}
+diff -Nur busybox-1.00/e2fsprogs/util.c busybox/e2fsprogs/util.c
+--- busybox-1.00/e2fsprogs/util.c      1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/util.c   2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,207 @@
++/*
++ * util.c --- helper functions used by tune2fs and mke2fs
++ * 
++ * Copyright 1995, 1996, 1997, 1998, 1999, 2000 by Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <string.h>
++#include <errno.h>
++#include <linux/major.h>
++#include <sys/stat.h>
++
++#include "e2fsbb.h"
++#include "e2p/e2p.h"
++#include "ext2fs/ext2_fs.h"
++#include "ext2fs/ext2fs.h"
++#include "blkid/blkid.h"
++#include "util.h"
++
++void proceed_question(void)
++{
++      fputs("Proceed anyway? (y,n) ", stdout);
++      if (bb_ask_confirmation() == 0)
++              exit(1);
++}
++
++void check_plausibility(const char *device)
++{
++      int val;
++#ifdef CONFIG_LFS
++      struct stat64 s;
++      val = stat64(device, &s);
++#else
++      struct stat s;
++      val = stat(device, &s);
++#endif
++
++      if(val == -1)
++              bb_perror_msg_and_die("Could not stat %s", device);
++      if (!S_ISBLK(s.st_mode)) {
++              printf("%s is not a block special device.\n", device);
++              proceed_question();
++              return;
++      }
++
++#ifdef HAVE_LINUX_MAJOR_H
++#ifndef MAJOR
++#define MAJOR(dev)    ((dev)>>8)
++#define MINOR(dev)    ((dev) & 0xff)
++#endif
++#ifndef SCSI_BLK_MAJOR
++#ifdef SCSI_DISK0_MAJOR
++#ifdef SCSI_DISK8_MAJOR
++#define SCSI_DISK_MAJOR(M) ((M) == SCSI_DISK0_MAJOR || \
++  ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR) || \
++  ((M) >= SCSI_DISK8_MAJOR && (M) <= SCSI_DISK15_MAJOR))
++#else
++#define SCSI_DISK_MAJOR(M) ((M) == SCSI_DISK0_MAJOR || \
++  ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR))
++#endif /* defined(SCSI_DISK8_MAJOR) */
++#define SCSI_BLK_MAJOR(M) (SCSI_DISK_MAJOR((M)) || (M) == SCSI_CDROM_MAJOR)
++#else
++#define SCSI_BLK_MAJOR(M)  ((M) == SCSI_DISK_MAJOR || (M) == SCSI_CDROM_MAJOR)
++#endif /* defined(SCSI_DISK0_MAJOR) */
++#endif /* defined(SCSI_BLK_MAJOR) */
++      if (((MAJOR(s.st_rdev) == HD_MAJOR &&
++            MINOR(s.st_rdev)%64 == 0) ||
++           (SCSI_BLK_MAJOR(MAJOR(s.st_rdev)) &&
++            MINOR(s.st_rdev)%16 == 0))) {
++              printf("%s is entire device, not just one partition!\n", device);
++              proceed_question();
++      }
++#endif
++}
++
++void check_mount(const char *device, int force, const char *type)
++{
++      errcode_t retval;
++      int mount_flags;
++
++      retval = ext2fs_check_if_mounted(device, &mount_flags);
++      if (retval) {
++              bb_error_msg("Could not determine if %s is mounted", device);
++              return;
++      }
++      if (!(mount_flags & EXT2_MF_MOUNTED))
++              return;
++
++      bb_error_msg("%s is mounted !", device);
++      if (force)
++              bb_error_msg("forcing anyways and ignoring /etc/mtab status");
++      else
++              bb_error_msg_and_die("will not make a %s here!", type);
++}
++
++void parse_journal_opts(char **journal_device, int *journal_flags, 
++                        int *journal_size, const char *opts)
++{
++      char *buf, *token, *next, *p, *arg;
++      int journal_usage = 0;
++#if 0
++      int     len;
++      len = strlen(opts);
++      buf = xmalloc(len+1);
++      strcpy(buf, opts);
++#else
++      buf = bb_xstrdup(opts);
++#endif
++      for (token = buf; token && *token; token = next) {
++              p = strchr(token, ',');
++              next = 0;
++              if (p) {
++                      *p = 0;
++                      next = p+1;
++              } 
++              arg = strchr(token, '=');
++              if (arg) {
++                      *arg = 0;
++                      arg++;
++              }
++              if (strcmp(token, "device") == 0) {
++                      *journal_device = blkid_get_devname(NULL, arg, NULL);
++                      if (!journal_device) {
++                              journal_usage++;
++                              continue;
++                      }
++              } else if (strcmp(token, "size") == 0) {
++                      if (!arg) {
++                              journal_usage++;
++                              continue;
++                      }
++                      (*journal_size) = strtoul(arg, &p, 0);
++                      if (*p)
++                              journal_usage++;
++              } else if (strcmp(token, "v1_superblock") == 0) {
++                      (*journal_flags) |= EXT2_MKJOURNAL_V1_SUPER;
++                      continue;
++              } else
++                      journal_usage++;
++      }
++      if (journal_usage)
++              bb_error_msg_and_die(
++                      "\nBad journal options specified.\n\n"
++                      "Journal options are separated by commas, "
++                      "and may take an argument which\n"
++                      "\tis set off by an equals ('=') sign.\n\n"
++                      "Valid journal options are:\n"
++                      "\tsize=<journal size in megabytes>\n"
++                      "\tdevice=<journal device>\n\n"
++                      "The journal size must be between "
++                      "1024 and 102400 filesystem blocks.\n\n");
++}     
++
++/*
++ * Determine the number of journal blocks to use, either via
++ * user-specified # of megabytes, or via some intelligently selected
++ * defaults.
++ * 
++ * Find a reasonable journal file size (in blocks) given the number of blocks
++ * in the filesystem.  For very small filesystems, it is not reasonable to
++ * have a journal that fills more than half of the filesystem.
++ */
++int figure_journal_size(int size, ext2_filsys fs)
++{
++      blk_t j_blocks;
++
++      if (fs->super->s_blocks_count < 2048) {
++              bb_error_msg("Filesystem too small for a journal");
++              return 0;
++      }
++
++      if (size >= 0) {
++              j_blocks = size * 1024 / (fs->blocksize / 1024);
++              if (j_blocks < 1024 || j_blocks > 102400)
++                      bb_error_msg_and_die("\nThe requested journal "
++                              "size is %d blocks;\n it must be "
++                              "between 1024 and 102400 blocks; Aborting",
++                              j_blocks);
++              if (j_blocks > fs->super->s_free_blocks_count)
++                      bb_error_msg_and_die("Journal size too big for filesystem");
++              return j_blocks;
++      }
++
++      if (fs->super->s_blocks_count < 32768)
++              j_blocks = 1024;
++      else if (fs->super->s_blocks_count < 262144)
++              j_blocks = 4096;
++      else
++              j_blocks = 8192;
++
++      return j_blocks;
++}
++
++void print_check_message(ext2_filsys fs)
++{
++      printf("This filesystem will be automatically "
++               "checked every %d mounts or\n"
++               "%g days, whichever comes first.  "
++               "Use tune2fs -c or -i to override.\n",
++             fs->super->s_max_mnt_count,
++             (double)fs->super->s_checkinterval / (3600 * 24));
++}
+diff -Nur busybox-1.00/e2fsprogs/util.h busybox/e2fsprogs/util.h
+--- busybox-1.00/e2fsprogs/util.h      1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/util.h   2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,18 @@
++/*
++ * util.h --- header file defining prototypes for helper functions
++ * used by tune2fs and mke2fs
++ * 
++ * Copyright 2000 by Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * This file may be redistributed under the terms of the GNU Public
++ * License.
++ * %End-Header%
++ */
++
++extern void proceed_question(void);
++extern void check_plausibility(const char *device);
++extern void parse_journal_opts(char **, int *, int *, const char *opts);
++extern void check_mount(const char *device, int force, const char *type);
++extern int figure_journal_size(int size, ext2_filsys fs);
++extern void print_check_message(ext2_filsys fs);
+diff -Nur busybox-1.00/e2fsprogs/uuid/clear.c busybox/e2fsprogs/uuid/clear.c
+--- busybox-1.00/e2fsprogs/uuid/clear.c        1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/uuid/clear.c     2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,43 @@
++/*
++ * clear.c -- Clear a UUID
++ * 
++ * Copyright (C) 1996, 1997 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, and the entire permission notice in its entirety,
++ *    including the disclaimer of warranties.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. The name of the author may not be used to endorse or promote
++ *    products derived from this software without specific prior
++ *    written permission.
++ * 
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * %End-Header%
++ */
++
++#include "string.h"
++
++#include "uuidP.h"
++
++void uuid_clear(uuid_t uu)
++{
++      memset(uu, 0, 16);
++}
++
+diff -Nur busybox-1.00/e2fsprogs/uuid/compare.c busybox/e2fsprogs/uuid/compare.c
+--- busybox-1.00/e2fsprogs/uuid/compare.c      1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/uuid/compare.c   2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,55 @@
++/*
++ * compare.c --- compare whether or not two UUID's are the same
++ *
++ * Returns 0 if the two UUID's are different, and 1 if they are the same.
++ * 
++ * Copyright (C) 1996, 1997 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, and the entire permission notice in its entirety,
++ *    including the disclaimer of warranties.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. The name of the author may not be used to endorse or promote
++ *    products derived from this software without specific prior
++ *    written permission.
++ * 
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * %End-Header%
++ */
++
++#include "uuidP.h"
++#include <string.h>
++
++#define UUCMP(u1,u2) if (u1 != u2) return((u1 < u2) ? -1 : 1);
++
++int uuid_compare(const uuid_t uu1, const uuid_t uu2)
++{
++      struct uuid     uuid1, uuid2;
++
++      uuid_unpack(uu1, &uuid1);
++      uuid_unpack(uu2, &uuid2);
++
++      UUCMP(uuid1.time_low, uuid2.time_low);
++      UUCMP(uuid1.time_mid, uuid2.time_mid);
++      UUCMP(uuid1.time_hi_and_version, uuid2.time_hi_and_version);
++      UUCMP(uuid1.clock_seq, uuid2.clock_seq);
++      return memcmp(uuid1.node, uuid2.node, 6);
++}
++
+diff -Nur busybox-1.00/e2fsprogs/uuid/copy.c busybox/e2fsprogs/uuid/copy.c
+--- busybox-1.00/e2fsprogs/uuid/copy.c 1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/uuid/copy.c      2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,45 @@
++/*
++ * copy.c --- copy UUIDs
++ * 
++ * Copyright (C) 1996, 1997 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, and the entire permission notice in its entirety,
++ *    including the disclaimer of warranties.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. The name of the author may not be used to endorse or promote
++ *    products derived from this software without specific prior
++ *    written permission.
++ * 
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * %End-Header%
++ */
++
++#include "uuidP.h"
++
++void uuid_copy(uuid_t dst, const uuid_t src)
++{
++      unsigned char           *cp1;
++      const unsigned char     *cp2;
++      int                     i;
++
++      for (i=0, cp1 = dst, cp2 = src; i < 16; i++)
++              *cp1++ = *cp2++;
++}
+diff -Nur busybox-1.00/e2fsprogs/uuid/gen_uuid.c busybox/e2fsprogs/uuid/gen_uuid.c
+--- busybox-1.00/e2fsprogs/uuid/gen_uuid.c     1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/uuid/gen_uuid.c  2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,310 @@
++/*
++ * gen_uuid.c --- generate a DCE-compatible uuid
++ *
++ * Copyright (C) 1996, 1997, 1998, 1999 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, and the entire permission notice in its entirety,
++ *    including the disclaimer of warranties.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. The name of the author may not be used to endorse or promote
++ *    products derived from this software without specific prior
++ *    written permission.
++ * 
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * %End-Header%
++ */
++
++#ifdef HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#ifdef HAVE_STDLIB_H
++#include <stdlib.h>
++#endif
++#include <string.h>
++#include <fcntl.h>
++#include <errno.h>
++#include <sys/types.h>
++#include <sys/time.h>
++#include <sys/stat.h>
++#include <sys/file.h>
++#ifdef HAVE_SYS_IOCTL_H
++#include <sys/ioctl.h>
++#endif
++#ifdef HAVE_SYS_SOCKET_H
++#include <sys/socket.h>
++#endif
++#ifdef HAVE_SYS_SOCKIO_H
++#include <sys/sockio.h>
++#endif
++#ifdef HAVE_NET_IF_H
++#include <net/if.h>
++#endif
++#ifdef HAVE_NETINET_IN_H
++#include <netinet/in.h>
++#endif
++#ifdef HAVE_NET_IF_DL_H
++#include <net/if_dl.h>
++#endif
++
++#include "uuidP.h"
++
++#ifdef HAVE_SRANDOM
++#define srand(x)      srandom(x)
++#define rand()                random()
++#endif
++
++static int get_random_fd(void)
++{
++      struct timeval  tv;
++      static int      fd = -2;
++      int             i;
++
++      if (fd == -2) {
++              gettimeofday(&tv, 0);
++              fd = open("/dev/urandom", O_RDONLY);
++              if (fd == -1)
++                      fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
++              srand((getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec);
++      }
++      /* Crank the random number generator a few times */
++      gettimeofday(&tv, 0);
++      for (i = (tv.tv_sec ^ tv.tv_usec) & 0x1F; i > 0; i--)
++              rand();
++      return fd;
++}
++
++
++/*
++ * Generate a series of random bytes.  Use /dev/urandom if possible,
++ * and if not, use srandom/random.
++ */
++static void get_random_bytes(void *buf, int nbytes)
++{
++      int i, n = nbytes, fd = get_random_fd();
++      int lose_counter = 0;
++      unsigned char *cp = (unsigned char *) buf;
++
++      if (fd >= 0) {
++              while (n > 0) {
++                      i = read(fd, cp, n);
++                      if (i <= 0) {
++                              if (lose_counter++ > 16)
++                                      break;
++                              continue;
++                      }
++                      n -= i;
++                      cp += i;
++                      lose_counter = 0;
++              }
++      }
++      
++      /*
++       * We do this all the time, but this is the only source of
++       * randomness if /dev/random/urandom is out to lunch.
++       */
++      for (cp = buf, i = 0; i < nbytes; i++)
++              *cp++ ^= (rand() >> 7) & 0xFF;
++      return;
++}
++
++/*
++ * Get the ethernet hardware address, if we can find it...
++ */
++static int get_node_id(unsigned char *node_id)
++{
++#ifdef HAVE_NET_IF_H
++      int             sd;
++      struct ifreq    ifr, *ifrp;
++      struct ifconf   ifc;
++      char buf[1024];
++      int             n, i;
++      unsigned char   *a;
++#ifdef HAVE_NET_IF_DL_H
++      struct sockaddr_dl *sdlp;
++#endif
++
++/*
++ * BSD 4.4 defines the size of an ifreq to be
++ * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
++ * However, under earlier systems, sa_len isn't present, so the size is 
++ * just sizeof(struct ifreq)
++ */
++#ifdef HAVE_SA_LEN
++#ifndef max
++#define max(a,b) ((a) > (b) ? (a) : (b))
++#endif
++#define ifreq_size(i) max(sizeof(struct ifreq),\
++     sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
++#else
++#define ifreq_size(i) sizeof(struct ifreq)
++#endif /* HAVE_SA_LEN*/
++
++      sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
++      if (sd < 0) {
++              return -1;
++      }
++      memset(buf, 0, sizeof(buf));
++      ifc.ifc_len = sizeof(buf);
++      ifc.ifc_buf = buf;
++      if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0) {
++              close(sd);
++              return -1;
++      }
++      n = ifc.ifc_len;
++      for (i = 0; i < n; i+= ifreq_size(*ifrp) ) {
++              ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i);
++              strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ);
++#ifdef SIOCGIFHWADDR
++              if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0)
++                      continue;
++              a = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
++#else
++#ifdef SIOCGENADDR
++              if (ioctl(sd, SIOCGENADDR, &ifr) < 0)
++                      continue;
++              a = (unsigned char *) ifr.ifr_enaddr;
++#else
++#ifdef HAVE_NET_IF_DL_H
++              sdlp = (struct sockaddr_dl *) &ifrp->ifr_addr;
++              if ((sdlp->sdl_family != AF_LINK) || (sdlp->sdl_alen != 6))
++                      continue;
++              a = (unsigned char *) &sdlp->sdl_data[sdlp->sdl_nlen];
++#else
++              /*
++               * XXX we don't have a way of getting the hardware
++               * address
++               */
++              close(sd);
++              return 0;
++#endif /* HAVE_NET_IF_DL_H */
++#endif /* SIOCGENADDR */
++#endif /* SIOCGIFHWADDR */
++              if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5])
++                      continue;
++              if (node_id) {
++                      memcpy(node_id, a, 6);
++                      close(sd);
++                      return 1;
++              }
++      }
++      close(sd);
++#endif
++      return 0;
++}
++
++/* Assume that the gettimeofday() has microsecond granularity */
++#define MAX_ADJUSTMENT 10
++
++static int get_clock(uint32_t *clock_high, uint32_t *clock_low, uint16_t *ret_clock_seq)
++{
++      static int                      adjustment = 0;
++      static struct timeval           last = {0, 0};
++      static uint16_t                 clock_seq;
++      struct timeval                  tv;
++      unsigned long long              clock_reg;
++      
++try_again:
++      gettimeofday(&tv, 0);
++      if ((last.tv_sec == 0) && (last.tv_usec == 0)) {
++              get_random_bytes(&clock_seq, sizeof(clock_seq));
++              clock_seq &= 0x3FFF;
++              last = tv;
++              last.tv_sec--;
++      }
++      if ((tv.tv_sec < last.tv_sec) ||
++          ((tv.tv_sec == last.tv_sec) &&
++           (tv.tv_usec < last.tv_usec))) {
++              clock_seq = (clock_seq+1) & 0x3FFF;
++              adjustment = 0;
++              last = tv;
++      } else if ((tv.tv_sec == last.tv_sec) &&
++          (tv.tv_usec == last.tv_usec)) {
++              if (adjustment >= MAX_ADJUSTMENT)
++                      goto try_again;
++              adjustment++;
++      } else {
++              adjustment = 0;
++              last = tv;
++      }
++              
++      clock_reg = tv.tv_usec*10 + adjustment;
++      clock_reg += ((unsigned long long) tv.tv_sec)*10000000;
++      clock_reg += (((unsigned long long) 0x01B21DD2) << 32) + 0x13814000;
++
++      *clock_high = clock_reg >> 32;
++      *clock_low = clock_reg;
++      *ret_clock_seq = clock_seq;
++      return 0;
++}
++
++void uuid_generate_time(uuid_t out)
++{
++      static unsigned char node_id[6];
++      static int has_init = 0;
++      struct uuid uu;
++      uint32_t        clock_mid;
++
++      if (!has_init) {
++              if (get_node_id(node_id) <= 0) {
++                      get_random_bytes(node_id, 6);
++                      /*
++                       * Set multicast bit, to prevent conflicts
++                       * with IEEE 802 addresses obtained from
++                       * network cards
++                       */
++                      node_id[0] |= 0x01;
++              }
++              has_init = 1;
++      }
++      get_clock(&clock_mid, &uu.time_low, &uu.clock_seq);
++      uu.clock_seq |= 0x8000;
++      uu.time_mid = (uint16_t) clock_mid;
++      uu.time_hi_and_version = ((clock_mid >> 16) & 0x0FFF) | 0x1000;
++      memcpy(uu.node, node_id, 6);
++      uuid_pack(&uu, out);
++}
++
++void uuid_generate_random(uuid_t out)
++{
++      uuid_t  buf;
++      struct uuid uu;
++
++      get_random_bytes(buf, sizeof(buf));
++      uuid_unpack(buf, &uu);
++
++      uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000;
++      uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF) | 0x4000;
++      uuid_pack(&uu, out);
++}
++
++/*
++ * This is the generic front-end to uuid_generate_random and
++ * uuid_generate_time.  It uses uuid_generate_random only if
++ * /dev/urandom is available, since otherwise we won't have
++ * high-quality randomness.
++ */
++void uuid_generate(uuid_t out)
++{
++      if (get_random_fd() >= 0)
++              uuid_generate_random(out);
++      else
++              uuid_generate_time(out);
++}
+diff -Nur busybox-1.00/e2fsprogs/uuid/isnull.c busybox/e2fsprogs/uuid/isnull.c
+--- busybox-1.00/e2fsprogs/uuid/isnull.c       1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/uuid/isnull.c    2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,48 @@
++/*
++ * isnull.c --- Check whether or not the UUID is null
++ * 
++ * Copyright (C) 1996, 1997 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, and the entire permission notice in its entirety,
++ *    including the disclaimer of warranties.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. The name of the author may not be used to endorse or promote
++ *    products derived from this software without specific prior
++ *    written permission.
++ * 
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * %End-Header%
++ */
++
++#include "uuidP.h"
++
++/* Returns 1 if the uuid is the NULL uuid */
++int uuid_is_null(const uuid_t uu)
++{
++      const unsigned char     *cp;
++      int                     i;
++
++      for (i=0, cp = uu; i < 16; i++)
++              if (*cp++)
++                      return 0;
++      return 1;
++}
++
+diff -Nur busybox-1.00/e2fsprogs/uuid/pack.c busybox/e2fsprogs/uuid/pack.c
+--- busybox-1.00/e2fsprogs/uuid/pack.c 1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/uuid/pack.c      2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,69 @@
++/*
++ * Internal routine for packing UUID's
++ * 
++ * Copyright (C) 1996, 1997 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, and the entire permission notice in its entirety,
++ *    including the disclaimer of warranties.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. The name of the author may not be used to endorse or promote
++ *    products derived from this software without specific prior
++ *    written permission.
++ * 
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * %End-Header%
++ */
++
++#include <string.h>
++#include "uuidP.h"
++
++void uuid_pack(const struct uuid *uu, uuid_t ptr)
++{
++      uint32_t        tmp;
++      unsigned char   *out = ptr;
++
++      tmp = uu->time_low;
++      out[3] = (unsigned char) tmp;
++      tmp >>= 8;
++      out[2] = (unsigned char) tmp;
++      tmp >>= 8;
++      out[1] = (unsigned char) tmp;
++      tmp >>= 8;
++      out[0] = (unsigned char) tmp;
++      
++      tmp = uu->time_mid;
++      out[5] = (unsigned char) tmp;
++      tmp >>= 8;
++      out[4] = (unsigned char) tmp;
++
++      tmp = uu->time_hi_and_version;
++      out[7] = (unsigned char) tmp;
++      tmp >>= 8;
++      out[6] = (unsigned char) tmp;
++
++      tmp = uu->clock_seq;
++      out[9] = (unsigned char) tmp;
++      tmp >>= 8;
++      out[8] = (unsigned char) tmp;
++
++      memcpy(out+10, uu->node, 6);
++}
++
+diff -Nur busybox-1.00/e2fsprogs/uuid/parse.c busybox/e2fsprogs/uuid/parse.c
+--- busybox-1.00/e2fsprogs/uuid/parse.c        1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/uuid/parse.c     2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,79 @@
++/*
++ * parse.c --- UUID parsing
++ * 
++ * Copyright (C) 1996, 1997 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, and the entire permission notice in its entirety,
++ *    including the disclaimer of warranties.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. The name of the author may not be used to endorse or promote
++ *    products derived from this software without specific prior
++ *    written permission.
++ * 
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * %End-Header%
++ */
++
++#include <stdlib.h>
++#include <stdio.h>
++#include <ctype.h>
++#include <string.h>
++
++#include "uuidP.h"
++
++int uuid_parse(const char *in, uuid_t uu)
++{
++      struct uuid     uuid;
++      int             i;
++      const char      *cp;
++      char            buf[3];
++
++      if (strlen(in) != 36)
++              return -1;
++      for (i=0, cp = in; i <= 36; i++,cp++) {
++              if ((i == 8) || (i == 13) || (i == 18) ||
++                  (i == 23)) {
++                      if (*cp == '-')
++                              continue;
++                      else
++                              return -1;
++              }
++              if (i== 36)
++                      if (*cp == 0)
++                              continue;
++              if (!isxdigit(*cp))
++                      return -1;
++      }
++      uuid.time_low = strtoul(in, NULL, 16);
++      uuid.time_mid = strtoul(in+9, NULL, 16);
++      uuid.time_hi_and_version = strtoul(in+14, NULL, 16);
++      uuid.clock_seq = strtoul(in+19, NULL, 16);
++      cp = in+24;
++      buf[2] = 0;
++      for (i=0; i < 6; i++) {
++              buf[0] = *cp++;
++              buf[1] = *cp++;
++              uuid.node[i] = strtoul(buf, NULL, 16);
++      }
++      
++      uuid_pack(&uuid, uu);
++      return 0;
++}
+diff -Nur busybox-1.00/e2fsprogs/uuid/unpack.c busybox/e2fsprogs/uuid/unpack.c
+--- busybox-1.00/e2fsprogs/uuid/unpack.c       1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/uuid/unpack.c    2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,63 @@
++/*
++ * Internal routine for unpacking UUID
++ * 
++ * Copyright (C) 1996, 1997 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, and the entire permission notice in its entirety,
++ *    including the disclaimer of warranties.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. The name of the author may not be used to endorse or promote
++ *    products derived from this software without specific prior
++ *    written permission.
++ * 
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * %End-Header%
++ */
++
++#include <string.h>
++#include "uuidP.h"
++
++void uuid_unpack(const uuid_t in, struct uuid *uu)
++{
++      const uint8_t   *ptr = in;
++      uint32_t                tmp;
++
++      tmp = *ptr++;
++      tmp = (tmp << 8) | *ptr++;
++      tmp = (tmp << 8) | *ptr++;
++      tmp = (tmp << 8) | *ptr++;
++      uu->time_low = tmp;
++
++      tmp = *ptr++;
++      tmp = (tmp << 8) | *ptr++;
++      uu->time_mid = tmp;
++      
++      tmp = *ptr++;
++      tmp = (tmp << 8) | *ptr++;
++      uu->time_hi_and_version = tmp;
++
++      tmp = *ptr++;
++      tmp = (tmp << 8) | *ptr++;
++      uu->clock_seq = tmp;
++
++      memcpy(uu->node, ptr, 6);
++}
++
+diff -Nur busybox-1.00/e2fsprogs/uuid/unparse.c busybox/e2fsprogs/uuid/unparse.c
+--- busybox-1.00/e2fsprogs/uuid/unparse.c      1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/uuid/unparse.c   2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,76 @@
++/*
++ * unparse.c -- convert a UUID to string
++ * 
++ * Copyright (C) 1996, 1997 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, and the entire permission notice in its entirety,
++ *    including the disclaimer of warranties.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. The name of the author may not be used to endorse or promote
++ *    products derived from this software without specific prior
++ *    written permission.
++ * 
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++
++#include "uuidP.h"
++
++static const char *fmt_lower = 
++      "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x";
++
++static const char *fmt_upper = 
++      "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X";
++
++#ifdef UUID_UNPARSE_DEFAULT_UPPER
++#define FMT_DEFAULT fmt_upper
++#else
++#define FMT_DEFAULT fmt_lower
++#endif
++
++static void uuid_unparse_x(const uuid_t uu, char *out, const char *fmt)
++{
++      struct uuid uuid;
++
++      uuid_unpack(uu, &uuid);
++      sprintf(out, fmt,
++              uuid.time_low, uuid.time_mid, uuid.time_hi_and_version,
++              uuid.clock_seq >> 8, uuid.clock_seq & 0xFF,
++              uuid.node[0], uuid.node[1], uuid.node[2],
++              uuid.node[3], uuid.node[4], uuid.node[5]);
++}
++
++void uuid_unparse_lower(const uuid_t uu, char *out)
++{
++      uuid_unparse_x(uu, out, fmt_lower);
++}
++
++void uuid_unparse_upper(const uuid_t uu, char *out)
++{
++      uuid_unparse_x(uu, out, fmt_upper);
++}
++
++void uuid_unparse(const uuid_t uu, char *out)
++{
++      uuid_unparse_x(uu, out, FMT_DEFAULT);
++}
+diff -Nur busybox-1.00/e2fsprogs/uuid/uuid.h busybox/e2fsprogs/uuid/uuid.h
+--- busybox-1.00/e2fsprogs/uuid/uuid.h 1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/uuid/uuid.h      2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,101 @@
++/*
++ * Public include file for the UUID library
++ * 
++ * Copyright (C) 1996, 1997, 1998 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, and the entire permission notice in its entirety,
++ *    including the disclaimer of warranties.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. The name of the author may not be used to endorse or promote
++ *    products derived from this software without specific prior
++ *    written permission.
++ * 
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * %End-Header%
++ */
++
++#ifndef _UUID_UUID_H
++#define _UUID_UUID_H
++
++#include <sys/types.h>
++#include <sys/time.h>
++#include <time.h>
++
++typedef unsigned char uuid_t[16];
++
++/* UUID Variant definitions */
++#define UUID_VARIANT_NCS      0
++#define UUID_VARIANT_DCE      1
++#define UUID_VARIANT_MICROSOFT        2
++#define UUID_VARIANT_OTHER    3
++
++/* UUID Type definitions */
++#define UUID_TYPE_DCE_TIME   1
++#define UUID_TYPE_DCE_RANDOM 4
++
++/* Allow UUID constants to be defined */
++#ifdef __GNUC__
++#define UUID_DEFINE(name,u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15) \
++      static const uuid_t name __attribute__ ((unused)) = {u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15}
++#else
++#define UUID_DEFINE(name,u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15) \
++      static const uuid_t name = {u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15}
++#endif
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/* clear.c */
++void uuid_clear(uuid_t uu);
++
++/* compare.c */
++int uuid_compare(const uuid_t uu1, const uuid_t uu2);
++
++/* copy.c */
++void uuid_copy(uuid_t dst, const uuid_t src);
++
++/* gen_uuid.c */
++void uuid_generate(uuid_t out);
++void uuid_generate_random(uuid_t out);
++void uuid_generate_time(uuid_t out);
++
++/* isnull.c */
++int uuid_is_null(const uuid_t uu);
++
++/* parse.c */
++int uuid_parse(const char *in, uuid_t uu);
++
++/* unparse.c */
++void uuid_unparse(const uuid_t uu, char *out);
++void uuid_unparse_lower(const uuid_t uu, char *out);
++void uuid_unparse_upper(const uuid_t uu, char *out);
++
++/* uuid_time.c */
++time_t uuid_time(const uuid_t uu, struct timeval *ret_tv);
++int uuid_type(const uuid_t uu);
++int uuid_variant(const uuid_t uu);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _UUID_UUID_H */
+diff -Nur busybox-1.00/e2fsprogs/uuid/uuidP.h busybox/e2fsprogs/uuid/uuidP.h
+--- busybox-1.00/e2fsprogs/uuid/uuidP.h        1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/uuid/uuidP.h     2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,63 @@
++/*
++ * uuid.h -- private header file for uuids
++ * 
++ * Copyright (C) 1996, 1997 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, and the entire permission notice in its entirety,
++ *    including the disclaimer of warranties.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. The name of the author may not be used to endorse or promote
++ *    products derived from this software without specific prior
++ *    written permission.
++ * 
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * %End-Header%
++ */
++
++#ifdef HAVE_INTTYPES_H
++#include <inttypes.h>
++#else
++#include <uuid/uuid_types.h>
++#endif
++#include <sys/types.h>
++
++#include "uuid.h"
++
++/*
++ * Offset between 15-Oct-1582 and 1-Jan-70
++ */
++#define TIME_OFFSET_HIGH 0x01B21DD2
++#define TIME_OFFSET_LOW  0x13814000
++
++struct uuid {
++      uint32_t        time_low;
++      uint16_t        time_mid;
++      uint16_t        time_hi_and_version;
++      uint16_t        clock_seq;
++      uint8_t node[6];
++};
++
++
++/*
++ * prototypes
++ */
++void uuid_pack(const struct uuid *uu, uuid_t ptr);
++void uuid_unpack(const uuid_t in, struct uuid *uu);
+diff -Nur busybox-1.00/e2fsprogs/uuid/uuid_time.c busybox/e2fsprogs/uuid/uuid_time.c
+--- busybox-1.00/e2fsprogs/uuid/uuid_time.c    1970-01-01 01:00:00.000000000 +0100
++++ busybox/e2fsprogs/uuid/uuid_time.c 2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,161 @@
++/*
++ * uuid_time.c --- Interpret the time field from a uuid.  This program
++ *    violates the UUID abstraction barrier by reaching into the guts
++ *    of a UUID and interpreting it.
++ * 
++ * Copyright (C) 1998, 1999 Theodore Ts'o.
++ *
++ * %Begin-Header%
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, and the entire permission notice in its entirety,
++ *    including the disclaimer of warranties.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. The name of the author may not be used to endorse or promote
++ *    products derived from this software without specific prior
++ *    written permission.
++ * 
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * %End-Header%
++ */
++
++#include <stdio.h>
++#include <unistd.h>
++#include <stdlib.h>
++#include <sys/types.h>
++#include <sys/time.h>
++#include <time.h>
++
++#include "uuidP.h"
++
++time_t uuid_time(const uuid_t uu, struct timeval *ret_tv)
++{
++      struct uuid             uuid;
++      uint32_t                        high;
++      struct timeval          tv;
++      unsigned long long      clock_reg;
++
++      uuid_unpack(uu, &uuid);
++      
++      high = uuid.time_mid | ((uuid.time_hi_and_version & 0xFFF) << 16);
++      clock_reg = uuid.time_low | ((unsigned long long) high << 32);
++
++      clock_reg -= (((unsigned long long) 0x01B21DD2) << 32) + 0x13814000;
++      tv.tv_sec = clock_reg / 10000000;
++      tv.tv_usec = (clock_reg % 10000000) / 10;
++
++      if (ret_tv)
++              *ret_tv = tv;
++
++      return tv.tv_sec;
++}
++
++int uuid_type(const uuid_t uu)
++{
++      struct uuid             uuid;
++
++      uuid_unpack(uu, &uuid); 
++      return ((uuid.time_hi_and_version >> 12) & 0xF);
++}
++
++int uuid_variant(const uuid_t uu)
++{
++      struct uuid             uuid;
++      int                     var;
++
++      uuid_unpack(uu, &uuid); 
++      var = uuid.clock_seq;
++
++      if ((var & 0x8000) == 0)
++              return UUID_VARIANT_NCS;
++      if ((var & 0x4000) == 0)
++              return UUID_VARIANT_DCE;
++      if ((var & 0x2000) == 0)
++              return UUID_VARIANT_MICROSOFT;
++      return UUID_VARIANT_OTHER;
++}
++
++#ifdef DEBUG
++static const char *variant_string(int variant)
++{
++      switch (variant) {
++      case UUID_VARIANT_NCS:
++              return "NCS";
++      case UUID_VARIANT_DCE:
++              return "DCE";
++      case UUID_VARIANT_MICROSOFT:
++              return "Microsoft";
++      default:
++              return "Other";
++      }
++}
++
++      
++int
++main(int argc, char **argv)
++{
++      uuid_t          buf;
++      time_t          time_reg;
++      struct timeval  tv;
++      int             type, variant;
++
++      if (argc != 2) {
++              fprintf(stderr, "Usage: %s uuid\n", argv[0]);
++              exit(1);
++      }
++      if (uuid_parse(argv[1], buf)) {
++              fprintf(stderr, "Invalid UUID: %s\n", argv[1]);
++              exit(1);
++      }
++      variant = uuid_variant(buf);
++      type = uuid_type(buf);
++      time_reg = uuid_time(buf, &tv);
++
++      printf("UUID variant is %d (%s)\n", variant, variant_string(variant));
++      if (variant != UUID_VARIANT_DCE) {
++              printf("Warning: This program only knows how to interpret "
++                     "DCE UUIDs.\n\tThe rest of the output is likely "
++                     "to be incorrect!!\n");
++      }
++      printf("UUID type is %d", type);
++      switch (type) {
++      case 1:
++              printf(" (time based)\n");
++              break;
++      case 2:
++              printf(" (DCE)\n");
++              break;
++      case 3:
++              printf(" (name-based)\n");
++              break;
++      case 4:
++              printf(" (random)\n");
++              break;
++      default:
++              printf("\n");
++      }
++      if (type != 1) {
++              printf("Warning: not a time-based UUID, so UUID time "
++                     "decoding will likely not work!\n");
++      }
++      printf("UUID time is: (%ld, %ld): %s\n", tv.tv_sec, tv.tv_usec,
++             ctime(&time_reg));
++      
++      return 0;
++}
++#endif
+diff -Nur busybox-1.00/editors/sed.c busybox/editors/sed.c
+--- busybox-1.00/editors/sed.c 2004-05-26 12:03:33.000000000 +0200
++++ busybox/editors/sed.c      2005-06-04 08:20:21.000000000 +0200
+@@ -34,7 +34,10 @@
+   resulting sed_cmd_t structures are appended to a linked list
+   (sed_cmd_head/sed_cmd_tail).
+-  process_file() does actual sedding, reading data lines from an input FILE *
++  add_input_file() adds a FILE * to the list of input files.  We need to
++  know them all ahead of time to find the last line for the $ match.
++
++  process_files() does actual sedding, reading data lines from each input FILE *
+   (which could be stdin) and applying the sed command list (sed_cmd_head) to
+   each of the resulting lines.
+@@ -54,7 +57,7 @@
+        - grouped commands: {cmd1;cmd2}
+        - transliteration (y/source-chars/dest-chars/)
+        - pattern space hold space storing / swapping (g, h, x)
+-       - labels / branching (: label, b, t)
++       - labels / branching (: label, b, t, T)
+        (Note: Specifying an address (range) to match is *optional*; commands
+        default to the whole pattern space if no specific address match was
+@@ -62,7 +65,7 @@
+       Unsupported features:
+-       - GNU extensions
++       - most GNU extensions
+        - and more.
+       Todo:
+@@ -112,17 +115,20 @@
+ /* globals */
+ /* options */
+-static int be_quiet = 0, in_place=0, regex_type=0;
+-FILE *nonstdout;
+-char *outname;
+-
++static int be_quiet, in_place, regex_type;
++static FILE *nonstdout;
++static char *outname,*hold_space;
++
++/* List of input files */
++static int input_file_count,current_input_file;
++static FILE **input_file_list;
+ static const char bad_format_in_subst[] =
+       "bad format in substitution expression";
+-const char *const semicolon_whitespace = "; \n\r\t\v";
++static const char *const semicolon_whitespace = "; \n\r\t\v";
+-regmatch_t regmatch[10];
+-static regex_t *previous_regex_ptr = NULL;
++static regmatch_t regmatch[10];
++static regex_t *previous_regex_ptr;
+ /* linked list of sed commands */
+ static sed_cmd_t sed_cmd_head;
+@@ -133,7 +139,7 @@
+       char *string;
+       struct append_list *next;
+ };
+-struct append_list *append_head=NULL, *append_tail=NULL;
++static struct append_list *append_head=NULL, *append_tail=NULL;
+ #ifdef CONFIG_FEATURE_CLEAN_UP
+ static void free_and_close_stuff(void)
+@@ -169,6 +175,11 @@
+               free(sed_cmd);
+               sed_cmd = sed_cmd_next;
+       }
++
++      if(hold_space) free(hold_space);
++
++    while(current_input_file<input_file_count)
++              fclose(input_file_list[current_input_file++]);
+ }
+ #endif
+@@ -429,7 +440,7 @@
+               if(sed_cmd->cmd=='w')
+                       sed_cmd->file=bb_xfopen(sed_cmd->string,"w");
+       /* handle branch commands */
+-      } else if (strchr(":bt", sed_cmd->cmd)) {
++      } else if (strchr(":btT", sed_cmd->cmd)) {
+               int length;
+               while(isspace(*cmdstr)) cmdstr++;
+@@ -471,7 +482,7 @@
+ /* Parse address+command sets, skipping comment lines. */
+-void add_cmd(char *cmdstr)
++static void add_cmd(char *cmdstr)
+ {
+       static char *add_cmd_line=NULL;
+       sed_cmd_t *sed_cmd;
+@@ -563,7 +574,9 @@
+       }
+ }
+-struct pipeline {
++/* Append to a string, reallocating memory as necessary. */
++
++static struct pipeline {
+       char *buf;      /* Space to hold string */
+       int idx;        /* Space used */
+       int len;        /* Space allocated */
+@@ -571,7 +584,7 @@
+ #define PIPE_GROW 64
+-void pipe_putc(char c)
++static void pipe_putc(char c)
+ {
+       if(pipeline.idx==pipeline.len) {
+               pipeline.buf = xrealloc(pipeline.buf, pipeline.len + PIPE_GROW);
+@@ -716,20 +729,29 @@
+       append_head=append_tail=NULL;
+ }
+-/* Get next line of input, flushing append buffer and noting if we hit EOF
+- * without a newline on the last line.
++static void add_input_file(FILE *file)
++{
++      input_file_list=xrealloc(input_file_list,(input_file_count+1)*sizeof(FILE *));
++      input_file_list[input_file_count++]=file;
++}
++
++/* Get next line of input from input_file_list, flushing append buffer and
++ * noting if we ran out of files without a newline on the last line we read.
+  */
+-static char *get_next_line(FILE * file, int *no_newline)
++static char *get_next_line(int *no_newline)
+ {
+-      char *temp;
++      char *temp=NULL;
+       int len;
+       flush_append();
+-      temp=bb_get_line_from_file(file);
+-      if(temp) {
+-              len=strlen(temp);
+-              if(len && temp[len-1]=='\n') temp[len-1]=0;
+-              else *no_newline=1;
++      while(current_input_file<input_file_count) {
++              temp=bb_get_line_from_file(input_file_list[current_input_file]);
++              if(temp) {
++                      len=strlen(temp);
++                      *no_newline=!(len && temp[len-1]=='\n');
++                      if(!*no_newline) temp[len-1]=0;
++                      break;
++              } else fclose(input_file_list[current_input_file++]);
+       }
+       return temp;
+@@ -755,15 +777,15 @@
+ #define sed_puts(s,n) missing_newline=puts_maybe_newline(s,nonstdout,missing_newline,n)
+-static void process_file(FILE *file)
++static void process_files(void)
+ {
+-      char *pattern_space, *next_line, *hold_space=NULL;
+-      static int linenum = 0, missing_newline=0;
++      char *pattern_space, *next_line;
++      int linenum = 0, missing_newline=0;
+       int no_newline,next_no_newline=0;
+-      next_line = get_next_line(file,&next_no_newline);
++      next_line = get_next_line(&next_no_newline);
+-      /* go through every line in the file */
++      /* go through every line in each file */
+       for(;;) {
+               sed_cmd_t *sed_cmd;
+               int substituted=0;
+@@ -773,7 +795,7 @@
+               no_newline=next_no_newline;
+               /* Read one line in advance so we can act on the last line, the '$' address */
+-              next_line = get_next_line(file,&next_no_newline);
++              next_line = get_next_line(&next_no_newline);
+               linenum++;
+ restart:
+               /* for every line, go through all the commands */
+@@ -908,7 +930,7 @@
+                                       /* Cut and paste text (replace) */
+                                       case 'c':
+                                               /* Only triggers on last line of a matching range. */
+-                                              if (!sed_cmd->in_match) sed_puts(sed_cmd->string,1);
++                                              if (!sed_cmd->in_match) sed_puts(sed_cmd->string,0);
+                                               goto discard_line;
+                                       /* Read file, append contents to output */
+@@ -942,7 +964,7 @@
+                                                       free(pattern_space);
+                                                       pattern_space = next_line;
+                                                       no_newline=next_no_newline;
+-                                                      next_line = get_next_line(file,&next_no_newline);
++                                                      next_line = get_next_line(&next_no_newline);
+                                                       linenum++;
+                                                       break;
+                                               }
+@@ -972,17 +994,21 @@
+                                                       pattern_space[len]='\n';
+                                                       strcpy(pattern_space+len+1, next_line);
+                                                       no_newline=next_no_newline;
+-                                                      next_line = get_next_line(file,&next_no_newline);
++                                                      next_line = get_next_line(&next_no_newline);
+                                                       linenum++;
+                                               }
+                                               break;
+                                       }
+-                                      /* Test if substition worked, branch if so. */
++                                      /* Test/branch if substitution occurred */
+                                       case 't':
+-                                              if (!substituted) break;
++                                              if(!substituted) break;
+                                               substituted=0;
+-                                                      /* Fall through */
++                                              /* Fall through */
++                                      /* Test/branch if substitution didn't occur */
++                                      case 'T':
++                                              if (substituted) break;
++                                              /* Fall through */
+                                       /* Branch to label */
+                                       case 'b':
+                                               if (!sed_cmd->string) goto discard_commands;
+@@ -1007,10 +1033,7 @@
+                                       }
+                                       case 'g':       /* Replace pattern space with hold space */
+                                               free(pattern_space);
+-                                              if (hold_space) {
+-                                                      pattern_space = strdup(hold_space);
+-                                                      no_newline=0;
+-                                              }
++                                              pattern_space = strdup(hold_space ? hold_space : "");
+                                               break;
+                                       case 'G':       /* Append newline and hold space to pattern space */
+                                       {
+@@ -1096,9 +1119,7 @@
+ extern int sed_main(int argc, char **argv)
+ {
+-      int status = EXIT_SUCCESS;
+-      int opt;
+-      uint8_t getpat = 1;
++      int status = EXIT_SUCCESS, opt, getpat = 1;
+ #ifdef CONFIG_FEATURE_CLEAN_UP
+       /* destroy command strings on exit */
+@@ -1153,8 +1174,7 @@
+               }
+       }
+-      /* if we didn't get a pattern from a -e and no command file was specified,
+-       * argv[optind] should be the pattern. no pattern, no worky */
++      /* if we didn't get a pattern from -e or -f, use argv[optind] */
+       if(getpat) {
+               if (argv[optind] == NULL)
+                       bb_show_usage();
+@@ -1171,49 +1191,47 @@
+        * files were specified or '-' was specified, take input from stdin.
+        * Otherwise, we process all the files specified. */
+       if (argv[optind] == NULL) {
+-              if(in_place) {
+-                      fprintf(stderr,"sed: Filename required for -i\n");
+-                      exit(1);
+-              }
+-              process_file(stdin);
++              if(in_place) bb_error_msg_and_die("Filename required for -i");
++              add_input_file(stdin);
++              process_files();
+       } else {
+               int i;
+               FILE *file;
+               for (i = optind; i < argc; i++) {
+                       if(!strcmp(argv[i], "-") && !in_place) {
+-                              process_file(stdin);
++                              add_input_file(stdin);
++                              process_files();
+                       } else {
+                               file = bb_wfopen(argv[i], "r");
+                               if (file) {
+                                       if(in_place) {
+                                               struct stat statbuf;
++                                              int nonstdoutfd;
++                                              
+                                               outname=bb_xstrndup(argv[i],strlen(argv[i])+6);
+                                               strcat(outname,"XXXXXX");
++                                              if(-1==(nonstdoutfd=mkstemp(outname)))
++                                                      bb_error_msg_and_die("no temp file");
++                                              nonstdout=fdopen(nonstdoutfd,"w");
+                                               /* Set permissions of output file */
+                                               fstat(fileno(file),&statbuf);
+-                                              mkstemp(outname);
+-                                              nonstdout=bb_wfopen(outname,"w");
+-                                              /* Set permissions of output file */
+-                                              fstat(fileno(file),&statbuf);
+-                                              fchmod(fileno(nonstdout),statbuf.st_mode);
+-                                              atexit(cleanup_outname);
+-                                      }
+-                                      process_file(file);
+-                                      fclose(file);
+-                                      if(in_place) {
++                                              fchmod(nonstdoutfd,statbuf.st_mode);
++                                              add_input_file(file);
++                                              process_files();
+                                               fclose(nonstdout);
+                                               nonstdout=stdout;
+                                               unlink(argv[i]);
+                                               rename(outname,argv[i]);
+                                               free(outname);
+                                               outname=0;
+-                                      }
++                                      } else add_input_file(file);
+                               } else {
+                                       status = EXIT_FAILURE;
+                               }
+                       }
+               }
++              if(input_file_count>current_input_file) process_files();
+       }
+       return status;
+diff -Nur busybox-1.00/editors/vi.c busybox/editors/vi.c
+--- busybox-1.00/editors/vi.c  2004-08-19 21:15:06.000000000 +0200
++++ busybox/editors/vi.c       2005-06-04 08:20:21.000000000 +0200
+@@ -19,7 +19,7 @@
+  */
+ static const char vi_Version[] =
+-      "$Id$";
++      "$Id$";
+ /*
+  * To compile for standalone use:
+@@ -2340,7 +2340,7 @@
+ }
+ //----- IO Routines --------------------------------------------
+-static Byte get_one_char()
++static Byte get_one_char(void)
+ {
+       static Byte c;
+@@ -2600,25 +2600,25 @@
+ }
+ //----- Erase from cursor to end of line -----------------------
+-static void clear_to_eol()
++static void clear_to_eol(void)
+ {
+       write1(Ceol);   // Erase from cursor to end of line
+ }
+ //----- Erase from cursor to end of screen -----------------------
+-static void clear_to_eos()
++static void clear_to_eos(void)
+ {
+       write1(Ceos);   // Erase from cursor to end of screen
+ }
+ //----- Start standout mode ------------------------------------
+-static void standout_start() // send "start reverse video" sequence
++static void standout_start(void) // send "start reverse video" sequence
+ {
+       write1(SOs);     // Start reverse video mode
+ }
+ //----- End standout mode --------------------------------------
+-static void standout_end() // send "end reverse video" sequence
++static void standout_end(void) // send "end reverse video" sequence
+ {
+       write1(SOn);     // End reverse video mode
+ }
+@@ -2648,7 +2648,7 @@
+ //----- Screen[] Routines --------------------------------------
+ //----- Erase the Screen[] memory ------------------------------
+-static void screen_erase()
++static void screen_erase(void)
+ {
+       memset(screen, ' ', screensize);        // clear new screen
+ }
+diff -Nur busybox-1.00/examples/depmod.pl busybox/examples/depmod.pl
+--- busybox-1.00/examples/depmod.pl    2004-03-15 09:28:33.000000000 +0100
++++ busybox/examples/depmod.pl 2005-06-04 08:20:22.000000000 +0200
+@@ -233,5 +233,5 @@
+ =cut
+-# $Id$
++# $Id$
+diff -Nur busybox-1.00/examples/zcip.script busybox/examples/zcip.script
+--- busybox-1.00/examples/zcip.script  1970-01-01 01:00:00.000000000 +0100
++++ busybox/examples/zcip.script       2005-06-04 08:20:22.000000000 +0200
+@@ -0,0 +1,38 @@
++#!/bin/sh
++
++# only for use as a "zcip" callback script
++if [ "x$interface" = x ]
++then
++      exit 1
++fi
++
++# zcip should start on boot/resume and various media changes
++case "$1" in
++init)
++      # for now, zcip requires the link to be already up,
++      # and it drops links when they go down.  that isn't
++      # the most robust model...
++      exit 0
++      ;;
++config)
++      if [ "x$ip" = x ]
++      then
++              exit 1
++      fi
++      # remember $ip for $interface, to use on restart
++      if [ "x$IP" != x -a -w "$IP.$interface" ]
++      then
++              echo $ip > "$IP.$interface"
++      fi
++      exec ip address add dev $interface \
++              scope link local "$ip/16" broadcast +
++      ;;
++deconfig)
++      if [ x$ip = x ]
++      then
++              exit 1
++      fi
++      exec ip address del dev $interface local $ip
++      ;;
++esac
++exit 1
+diff -Nur busybox-1.00/findutils/find.c busybox/findutils/find.c
+--- busybox-1.00/findutils/find.c      2004-03-15 09:28:37.000000000 +0100
++++ busybox/findutils/find.c   2005-06-04 08:20:20.000000000 +0200
+@@ -59,7 +59,7 @@
+ #endif
+ #ifdef CONFIG_FEATURE_FIND_NEWER
+-time_t newer_mtime;
++static time_t newer_mtime;
+ #endif
+ #ifdef CONFIG_FEATURE_FIND_INUM
+diff -Nur busybox-1.00/findutils/grep.c busybox/findutils/grep.c
+--- busybox-1.00/findutils/grep.c      2004-10-08 10:10:57.000000000 +0200
++++ busybox/findutils/grep.c   2005-06-04 08:20:20.000000000 +0200
+@@ -98,7 +98,7 @@
+       }
+       last_line_printed = linenum;
+ #endif
+-      if (print_filename)
++      if (print_filename > 0)
+               printf("%s%c", cur_file, decoration);
+       if (print_line_num)
+               printf("%i%c", linenum, decoration);
+@@ -219,7 +219,7 @@
+       /* grep -c: print [filename:]count, even if count is zero */
+       if (print_match_counts) {
+-              if (print_filename)
++              if (print_filename > 0)
+                       printf("%s:", cur_file);
+                   printf("%d\n", nmatches);
+       }
+diff -Nur busybox-1.00/include/applets.h busybox/include/applets.h
+--- busybox-1.00/include/applets.h     2004-08-27 01:01:34.000000000 +0200
++++ busybox/include/applets.h  2005-06-04 08:20:17.000000000 +0200
+@@ -16,40 +16,41 @@
+ #if defined(PROTOTYPES)
+-  #define APPLET(a,b,c,d) extern int b(int argc, char **argv);
+-  #define APPLET_NOUSAGE(a,b,c,d) extern int b(int argc, char **argv);
+-  #define APPLET_ODDNAME(a,b,c,d,e) extern int b(int argc, char **argv);
++# define APPLET(a,b,c,d) extern int b(int argc, char **argv);
++# define APPLET_NOUSAGE(a,b,c,d) extern int b(int argc, char **argv);
++# define APPLET_ODDNAME(a,b,c,d,e) extern int b(int argc, char **argv);
+   extern const char usage_messages[];
+ #elif defined(MAKE_USAGE)
+-  #ifdef CONFIG_FEATURE_VERBOSE_USAGE
+-    #define APPLET(a,b,c,d) a##_trivial_usage "\n\n" a##_full_usage "\0"
+-    #define APPLET_NOUSAGE(a,b,c,d) "\b\0"
+-    #define APPLET_ODDNAME(a,b,c,d,e) e##_trivial_usage "\n\n" e##_full_usage "\0"
+-  #else
+-    #define APPLET(a,b,c,d) a##_trivial_usage "\0"
+-    #define APPLET_NOUSAGE(a,b,c,d) "\b\0"
+-    #define APPLET_ODDNAME(a,b,c,d,e) e##_trivial_usage "\0"
+-  #endif
++# ifdef CONFIG_FEATURE_VERBOSE_USAGE
++#  define APPLET(a,b,c,d) a##_trivial_usage "\n\n" a##_full_usage "\0"
++#  define APPLET_NOUSAGE(a,b,c,d) "\b\0"
++#  define APPLET_ODDNAME(a,b,c,d,e) e##_trivial_usage "\n\n" e##_full_usage "\0"
++# else
++#  define APPLET(a,b,c,d) a##_trivial_usage "\0"
++#  define APPLET_NOUSAGE(a,b,c,d) "\b\0"
++#  define APPLET_ODDNAME(a,b,c,d,e) e##_trivial_usage "\0"
++# endif
+ #elif defined(MAKE_LINKS)
+-#  define APPLET(a,b,c,d) LINK c a
+-#  define APPLET_NOUSAGE(a,b,c,d) LINK c a
+-#  define APPLET_ODDNAME(a,b,c,d,e) LINK c a
++# define APPLET(a,b,c,d) LINK c a
++# define APPLET_NOUSAGE(a,b,c,d) LINK c a
++# define APPLET_ODDNAME(a,b,c,d,e) LINK c a
+ #else
+   const struct BB_applet applets[] = {
+-  #define APPLET(a,b,c,d) {#a,b,c,d},
+-  #define APPLET_NOUSAGE(a,b,c,d) {a,b,c,d},
+-  #define APPLET_ODDNAME(a,b,c,d,e) {a,b,c,d},
++# define APPLET(a,b,c,d) {#a,b,c,d},
++# define APPLET_NOUSAGE(a,b,c,d) {a,b,c,d},
++# define APPLET_ODDNAME(a,b,c,d,e) {a,b,c,d},
+ #endif
+ #ifdef CONFIG_INSTALL_NO_USR
+-#define _BB_DIR_USR_BIN _BB_DIR_BIN
+-#define _BB_DIR_USR_SBIN _BB_DIR_SBIN
++# define _BB_DIR_USR_BIN _BB_DIR_BIN
++# define _BB_DIR_USR_SBIN _BB_DIR_SBIN
+ #endif
+ #ifdef CONFIG_TEST
+       APPLET_NOUSAGE("[", test_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
++      APPLET_NOUSAGE("[[", test_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
+ #endif
+ #ifdef CONFIG_ADDGROUP
+       APPLET(addgroup, addgroup_main, _BB_DIR_BIN, _BB_SUID_NEVER)
+@@ -88,6 +89,9 @@
+ #ifdef CONFIG_CAT
+       APPLET(cat, cat_main, _BB_DIR_BIN, _BB_SUID_NEVER)
+ #endif
++#ifdef CONFIG_CHATTR
++      APPLET(chattr, chattr_main, _BB_DIR_BIN, _BB_SUID_NEVER)
++#endif
+ #ifdef CONFIG_CHGRP
+       APPLET(chgrp, chgrp_main, _BB_DIR_BIN, _BB_SUID_NEVER)
+ #endif
+@@ -109,6 +113,9 @@
+ #ifdef CONFIG_CMP
+       APPLET(cmp, cmp_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
+ #endif
++#ifdef CONFIG_COMM
++      APPLET(comm, comm_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
++#endif
+ #ifdef CONFIG_CP
+       APPLET(cp, cp_main, _BB_DIR_BIN, _BB_SUID_NEVER)
+ #endif
+@@ -170,7 +177,7 @@
+       APPLET(dumpkmap, dumpkmap_main, _BB_DIR_BIN, _BB_SUID_NEVER)
+ #endif
+ #ifdef CONFIG_DUMPLEASES
+-        APPLET(dumpleases, dumpleases_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
++      APPLET(dumpleases, dumpleases_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
+ #endif
+ #ifdef CONFIG_ECHO
+       APPLET(echo, echo_main, _BB_DIR_BIN, _BB_SUID_NEVER)
+@@ -178,12 +185,21 @@
+ #if defined(CONFIG_FEATURE_GREP_EGREP_ALIAS)
+       APPLET_NOUSAGE("egrep", grep_main, _BB_DIR_BIN, _BB_SUID_NEVER)
+ #endif
++#ifdef CONFIG_EJECT
++      APPLET(eject, eject_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
++#endif
+ #ifdef CONFIG_ENV
+       APPLET(env, env_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
+ #endif
++#ifdef CONFIG_ETHER_WAKE
++      APPLET_ODDNAME("ether-wake", etherwake_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER, ether_wake)
++#endif
+ #ifdef CONFIG_EXPR
+       APPLET(expr, expr_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
+ #endif
++#ifdef CONFIG_FAKEIDENTD
++      APPLET(fakeidentd, fakeidentd_main, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)
++#endif
+ #ifdef CONFIG_FALSE
+       APPLET(false, false_main, _BB_DIR_BIN, _BB_SUID_NEVER)
+ #endif
+@@ -355,6 +371,9 @@
+ #ifdef CONFIG_LS
+       APPLET(ls, ls_main, _BB_DIR_BIN, _BB_SUID_NEVER)
+ #endif
++#ifdef CONFIG_LSATTR
++      APPLET(lsattr, lsattr_main, _BB_DIR_BIN, _BB_SUID_NEVER)
++#endif
+ #ifdef CONFIG_LSMOD
+       APPLET(lsmod, lsmod_main, _BB_DIR_SBIN, _BB_SUID_NEVER)
+ #endif
+@@ -412,6 +431,9 @@
+ #ifdef CONFIG_NETSTAT
+       APPLET(netstat, netstat_main, _BB_DIR_BIN, _BB_SUID_NEVER)
+ #endif
++#ifdef CONFIG_NICE
++      APPLET(nice, nice_main, _BB_DIR_BIN, _BB_SUID_NEVER)
++#endif
+ #ifdef CONFIG_NSLOOKUP
+       APPLET(nslookup, nslookup_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
+ #endif
+@@ -440,11 +462,14 @@
+       APPLET_NOUSAGE("pipe_progress", pipe_progress_main, _BB_DIR_BIN, _BB_SUID_NEVER)
+ #endif
+ #ifdef CONFIG_PIVOT_ROOT
+-      APPLET(pivot_root, pivot_root_main, _BB_DIR_SBIN, _BB_SUID_NEVER)
++      APPLET(pivot_root, pivot_root_main, _BB_DIR_SBIN, _BB_SUID_NEVER)
+ #endif
+ #ifdef CONFIG_POWEROFF
+       APPLET(poweroff, poweroff_main, _BB_DIR_SBIN, _BB_SUID_NEVER)
+ #endif
++#ifdef CONFIG_PRINTENV
++      APPLET(printenv, printenv_main, _BB_DIR_BIN, _BB_SUID_NEVER)
++#endif
+ #ifdef CONFIG_PRINTF
+       APPLET(printf, printf_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
+ #endif
+@@ -460,6 +485,9 @@
+ #ifdef CONFIG_READLINK
+       APPLET(readlink, readlink_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
+ #endif
++#ifdef CONFIG_READPROFILE
++      APPLET(readprofile, readprofile_main, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)
++#endif
+ #ifdef CONFIG_REALPATH
+       APPLET(realpath, realpath_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
+ #endif
+@@ -482,7 +510,7 @@
+       APPLET(rmmod, rmmod_main, _BB_DIR_SBIN, _BB_SUID_NEVER)
+ #endif
+ #ifdef CONFIG_ROUTE
+-      APPLET(route, route_main, _BB_DIR_SBIN, _BB_SUID_NEVER)
++      APPLET(route, route_main, _BB_DIR_SBIN, _BB_SUID_NEVER)
+ #endif
+ #ifdef CONFIG_RPM
+       APPLET(rpm, rpm_main, _BB_DIR_BIN, _BB_SUID_NEVER)
+@@ -524,7 +552,10 @@
+       APPLET(sort, sort_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
+ #endif
+ #ifdef CONFIG_START_STOP_DAEMON
+-    APPLET_ODDNAME("start-stop-daemon", start_stop_daemon_main, _BB_DIR_SBIN, _BB_SUID_NEVER, start_stop_daemon)
++      APPLET_ODDNAME("start-stop-daemon", start_stop_daemon_main, _BB_DIR_SBIN, _BB_SUID_NEVER, start_stop_daemon)
++#endif
++#ifdef CONFIG_STAT
++      APPLET(stat, stat_main, _BB_DIR_BIN, _BB_SUID_NEVER)
+ #endif
+ #ifdef CONFIG_STRINGS
+       APPLET(strings, strings_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
+@@ -538,6 +569,9 @@
+ #ifdef CONFIG_SULOGIN
+       APPLET(sulogin, sulogin_main, _BB_DIR_SBIN, _BB_SUID_NEVER)
+ #endif
++#ifdef CONFIG_SUM
++      APPLET(sum, sum_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
++#endif
+ #ifdef CONFIG_SWAPONOFF
+       APPLET(swapoff, swap_on_off_main, _BB_DIR_SBIN, _BB_SUID_NEVER)
+ #endif
+@@ -599,7 +633,7 @@
+       APPLET(udhcpc, udhcpc_main, _BB_DIR_SBIN, _BB_SUID_NEVER)
+ #endif
+ #ifdef CONFIG_UDHCPD
+-        APPLET(udhcpd, udhcpd_main, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)
++      APPLET(udhcpd, udhcpd_main, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)
+ #endif
+ #ifdef CONFIG_UMOUNT
+       APPLET(umount, umount_main, _BB_DIR_BIN, _BB_SUID_NEVER)
+@@ -670,6 +704,9 @@
+ #ifdef CONFIG_GUNZIP
+       APPLET(zcat, gunzip_main, _BB_DIR_BIN, _BB_SUID_NEVER)
+ #endif
++#ifdef CONFIG_ZCIP
++      APPLET(zcip, zcip_main, _BB_DIR_SBIN, _BB_SUID_NEVER)
++#endif
+ #if !defined(PROTOTYPES) && !defined(MAKE_USAGE)
+       { 0,NULL,0 }
+diff -Nur busybox-1.00/include/busybox.h busybox/include/busybox.h
+--- busybox-1.00/include/busybox.h     2004-03-15 09:28:38.000000000 +0100
++++ busybox/include/busybox.h  2005-06-04 08:20:17.000000000 +0200
+@@ -32,10 +32,10 @@
+ #include <sys/stat.h>
+ #include <sys/types.h>
+-#if __GNU_LIBRARY__ < 5
+-#ifndef __dietlibc__
+-#error "Sorry, libc5 is not supported"
+-#endif
++#if __GNU_LIBRARY__ < 5 && \
++    !defined(__dietlibc__) && \
++    !defined(_NEWLIB_VERSION)
++#error "Sorry, this libc version is not supported :("
+ #endif
+ #ifndef BB_EXTRA_VERSION
+diff -Nur busybox-1.00/include/inet_common.h busybox/include/inet_common.h
+--- busybox-1.00/include/inet_common.h 2004-03-10 08:42:37.000000000 +0100
++++ busybox/include/inet_common.h      2005-06-04 08:20:17.000000000 +0200
+@@ -4,7 +4,7 @@
+  *
+  * Heavily modified by Manuel Novoa III       Mar 12, 2001
+  *
+- * Version:     $Id$
++ * Version:     $Id$
+  *
+  */
+@@ -29,5 +29,7 @@
+ extern int INET_rresolve(char *name, size_t len, struct sockaddr_in *s_in,
+                        int numeric, unsigned int netmask);
++#ifdef CONFIG_FEATURE_IPV6
+ extern int INET6_resolve(const char *name, struct sockaddr_in6 *sin6);
+ extern int INET6_rresolve(char *name, size_t len, struct sockaddr_in6 *sin6, int numeric);
++#endif
+diff -Nur busybox-1.00/include/libbb.h busybox/include/libbb.h
+--- busybox-1.00/include/libbb.h       2004-09-15 05:04:07.000000000 +0200
++++ busybox/include/libbb.h    2005-06-04 08:20:17.000000000 +0200
+@@ -43,7 +43,7 @@
+ #include "config.h"
+ #ifdef CONFIG_SELINUX
+-#include <proc_secure.h>
++#include <selinux/selinux.h>  
+ #endif
+ #include "pwd_.h"
+@@ -137,6 +137,7 @@
+ extern char *find_real_root_device_name(void);
+ extern char *bb_get_line_from_file(FILE *file);
+ extern char *bb_get_chomped_line_from_file(FILE *file);
++extern char *bb_get_chunk_from_file(FILE *file);
+ extern int bb_copyfd_size(int fd1, int fd2, const off_t size);
+ extern int bb_copyfd_eof(int fd1, int fd2);
+ extern void  bb_xprint_and_close_file(FILE *file);
+@@ -150,6 +151,7 @@
+ extern int   bb_fclose_nonstdin(FILE *f);
+ extern void  bb_fflush_stdout_and_exit(int retval) __attribute__ ((noreturn));
++#define BB_GETOPT_ERROR 0x80000000UL
+ extern const char *bb_opt_complementaly;
+ extern const struct option *bb_applet_long_options;
+ extern unsigned long bb_getopt_ulflags(int argc, char **argv, const char *applet_opts, ...);
+@@ -323,6 +325,7 @@
+ extern const char * const bb_msg_memory_exhausted;
+ extern const char * const bb_msg_invalid_date;
+ extern const char * const bb_msg_io_error;
++extern const char * const bb_msg_read_error;
+ extern const char * const bb_msg_write_error;
+ extern const char * const bb_msg_name_longer_than_foo;
+ extern const char * const bb_msg_unknown;
+@@ -421,11 +424,11 @@
+ #define FAIL_DELAY    3
+ extern void change_identity ( const struct passwd *pw );
+ extern const char *change_identity_e2str ( const struct passwd *pw );
+-extern void run_shell ( const char *shell, int loginshell, const char *command, const char **additional_args
++extern void run_shell ( const char *shell, int loginshell, const char *command, const char **additional_args);
+ #ifdef CONFIG_SELINUX
+-      , security_id_t sid
+-#endif
+-);
++extern void renew_current_security_context(void);
++extern void set_current_security_context(security_context_t sid);
++#endif 
+ extern int run_parts(char **args, const unsigned char test_mode, char **env);
+ extern int restricted_shell ( const char *shell );
+ extern void setup_environment ( const char *shell, int loginshell, int changeenv, const struct passwd *pw );
+@@ -456,11 +459,7 @@
+       char short_cmd[16];
+ } procps_status_t;
+-extern procps_status_t * procps_scan(int save_user_arg0
+-#ifdef CONFIG_SELINUX
+-      , int use_selinux, security_id_t *sid
+-#endif
+-);
++extern procps_status_t * procps_scan(int save_user_arg0);
+ extern unsigned short compare_string_array(const char *string_array[], const char *key);
+ extern int my_query_module(const char *name, int which, void **buf, size_t *bufsize, size_t *ret);
+diff -Nur busybox-1.00/include/usage.h busybox/include/usage.h
+--- busybox-1.00/include/usage.h       2004-09-14 18:23:56.000000000 +0200
++++ busybox/include/usage.h    2005-06-04 08:20:17.000000000 +0200
+@@ -46,7 +46,7 @@
+       "\t-v\t\tverbosely list files processed"
+ #define arping_trivial_usage \
+-      "[-fqbDUA] [-c count] [-w timeout] [-I device] [-s sender] target\n"
++      "[-fqbDUA] [-c count] [-w timeout] [-I device] [-s sender] target"
+ #define arping_full_usage \
+       "Ping hosts by ARP requests/replies.\n\n" \
+       "Options:\n" \
+@@ -64,7 +64,7 @@
+ #define ash_trivial_usage \
+       "[FILE]...\n" \
+-      "or: ash -c command [args]...\n"
++      "or: ash -c command [args]..."
+ #define ash_full_usage \
+       "The ash shell (command interpreter)"
+@@ -103,12 +103,12 @@
+       "Uncompress to stdout."
+ #define cal_trivial_usage \
+-       "[-jy] [[month] year]"
++      "[-jy] [[month] year]"
+ #define cal_full_usage \
+-       "Display a calendar.\n" \
+-       "\nOptions:\n" \
+-       "\t-j\tUse julian dates.\n" \
+-       "\t-y\tDisplay the entire year."
++      "Display a calendar.\n" \
++      "\nOptions:\n" \
++      "\t-j\tUse julian dates\n" \
++      "\t-y\tDisplay the entire year"
+ #define cat_trivial_usage \
+       "[-u] [FILE]..."
+@@ -120,12 +120,36 @@
+       "$ cat /proc/uptime\n" \
+       "110716.72 17.67"
++#define chattr_trivial_usage \
++      "[-R] [-+=AacDdijsStTu] [-v version] files..."
++#define chattr_full_usage \
++      "change file attributes on an ext2 fs\n\n" \
++      "Modifiers:\n" \
++      "\t-\tremove attributes\n" \
++      "\t+\tadd attributes\n" \
++      "\t=\tset attributes\n" \
++      "Attributes:\n" \
++      "\tA\tdon't track atime\n" \
++      "\ta\tappend mode only\n" \
++      "\tc\tenable compress\n" \
++      "\tD\twrite dir contents synchronously\n" \
++      "\td\tdo not backup with dump\n" \
++      "\ti\tcannot be modified (immutable)\n" \
++      "\tj\twrite all data to journal first\n" \
++      "\ts\tzero disk storage when deleted\n" \
++      "\tS\twrite file contents synchronously\n" \
++      "\tt\tdisable tail-merging of partial blocks with other files\n" \
++      "\tu\tallow file to be undeleted\n" \
++      "Options:\n" \
++      "\t-R\trecursively list subdirectories\n" \
++      "\t-v\tset the file's version/generation number"
++
+ #define chgrp_trivial_usage \
+       "[OPTION]... GROUP FILE..."
+ #define chgrp_full_usage \
+       "Change the group membership of each FILE to GROUP.\n" \
+       "\nOptions:\n" \
+-      "\t-R\tChanges files and directories recursively."
++      "\t-R\tChanges files and directories recursively"
+ #define chgrp_example_usage \
+       "$ ls -l /tmp/foo\n" \
+       "-r--r--r--    1 andersen andersen        0 Apr 12 18:25 /tmp/foo\n" \
+@@ -139,7 +163,7 @@
+       "Each MODE is one or more of the letters ugoa, one of the\n" \
+       "symbols +-= and one or more of the letters rwxst.\n\n" \
+       "Options:\n" \
+-      "\t-R\tChanges files and directories recursively."
++      "\t-R\tChanges files and directories recursively"
+ #define chmod_example_usage \
+       "$ ls -l /tmp/foo\n" \
+       "-rw-rw-r--    1 root     root            0 Apr 12 18:25 /tmp/foo\n" \
+@@ -155,8 +179,8 @@
+ #define chown_full_usage \
+       "Change the owner and/or group of each FILE to OWNER and/or GROUP.\n" \
+       "\nOptions:\n" \
+-      "\t-R\tChanges files and directories recursively.\n" \
+-      "\t-h\tDo not dereference symbolic links."
++      "\t-R\tChanges files and directories recursively\n" \
++      "\t-h\tDo not dereference symbolic links"
+ #define chown_example_usage \
+       "$ ls -l /tmp/foo\n" \
+       "-r--r--r--    1 andersen andersen        0 Apr 12 18:25 /tmp/foo\n" \
+@@ -192,19 +216,29 @@
+ #define cmp_trivial_usage \
+       "[-l] [-s] FILE1 [FILE2]"
+ #define cmp_full_usage \
+-      "Compare files.  Compares FILE1 vs stdin if FILE2 is not specified.\n\n" \
++      "Compares FILE1 vs stdin if FILE2 is not specified.\n\n" \
+       "Options:\n" \
+       "\t-l\tWrite the byte numbers (decimal) and values (octal)\n" \
+-      "\t\t  for all differing bytes.\n" \
++      "\t\t  for all differing bytes\n" \
+       "\t-s\tquiet mode - do not print"
++#define comm_trivial_usage \
++      "[-123] FILE1 FILE2"
++#define comm_full_usage \
++      "Compares FILE1 to FILE2, or to stdin if = is specified.\n\n" \
++      "Options:\n" \
++      "\t-1\tSuppress lines unique to FILE1\n" \
++      "\t-2\tSuppress lines unique to FILE2\n" \
++      "\t-3\tSuppress lines common to both files"
++
+ #define cp_trivial_usage \
+       "[OPTION]... SOURCE DEST"
+ #define cp_full_usage \
+       "Copies SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.\n" \
+       "\n" \
+       "\t-a\tSame as -dpR\n" \
+-      "\t-d\tPreserves links\n" \
++      "\t-d,-P\tPreserves links\n" \
++      "\t-H,-L\tDereference all symlinks (implied by default)\n" \
+       "\t-p\tPreserves file attributes if possible\n" \
+       "\t-f\tforce (implied; ignored) - always set\n" \
+       "\t-i\tinteractive, prompt before overwrite\n" \
+@@ -259,9 +293,9 @@
+       "\t-f N\t\tPrint only these fields\n" \
+       "\t-n\t\tIgnored"
+ #define cut_example_usage \
+-      "$ echo "Hello world" | cut -f 1 -d ' '\n" \
++      "$ echo \"Hello world\" | cut -f 1 -d ' '\n" \
+       "Hello\n" \
+-      "$ echo "Hello world" | cut -f 2 -d ' '\n" \
++      "$ echo \"Hello world\" | cut -f 2 -d ' '\n" \
+       "world\n"
+ #ifdef CONFIG_FEATURE_DATE_ISOFMT
+@@ -277,10 +311,10 @@
+       "\nOptions:\n" \
+       "\t-R\t\tOutputs RFC-822 compliant date string\n" \
+       "\t-d STRING\tDisplays time described by STRING, not `now'\n" \
+-      USAGE_DATE_ISOFMT("\t-I[TIMESPEC]\tOutputs an ISO-8601 compliant date/time string.\n" \
++      USAGE_DATE_ISOFMT("\t-I[TIMESPEC]\tOutputs an ISO-8601 compliant date/time string\n" \
+       "\t\t\tTIMESPEC=`date' (or missing) for date only,\n" \
+       "\t\t\t`hours', `minutes', or `seconds' for date and,\n" \
+-      "\t\t\ttime to the indicated precision.\n") \
++      "\t\t\ttime to the indicated precision\n") \
+       "\t-s\t\tSets time described by STRING\n" \
+       "\t-r FILE\t\tDisplays the last modification time of FILE\n" \
+       "\t-u\t\tPrints or sets Coordinated Universal Time"
+@@ -292,14 +326,14 @@
+       "expression ..."
+ #define dc_full_usage \
+       "This is a Tiny RPN calculator that understands the\n" \
+-      "following operations: +, add, -, sub, *, mul, /, div, %, mod, "\
++      "following operations: +, add, -, sub, *, mul, /, div, %, mod, " \
+       "**, exp, and, or, not, eor.\n" \
+       "For example: 'dc 2 2 add' -> 4, and 'dc 8 8 \\* 2 2 + /' -> 16.\n" \
+       "\nOptions:\n" \
+-      "p - Prints the value on the top of the stack, without altering the stack.\n" \
+-      "f - Prints the entire contents of the stack without altering anything.\n" \
+-      "o - Pops the value off the top of the stack and uses it to set the output radix.\n" \
+-      "    Only 10 and 16 are supported."
++      "p - Prints the value on the top of the stack, without altering the stack\n" \
++      "f - Prints the entire contents of the stack without altering anything\n" \
++      "o - Pops the value off the top of the stack and uses it to set the output radix\n" \
++      "    Only 10 and 16 are supported"
+ #define dc_example_usage \
+       "$ dc 2 2 + p\n" \
+       "4\n" \
+@@ -328,7 +362,7 @@
+       "\tconv=sync\tpad blocks with zeros\n" \
+       "\n" \
+       "Numbers may be suffixed by c (x1), w (x2), b (x512), kD (x1000), k (x1024),\n" \
+-      "MD (x1000000), M (x1048576), GD (x1000000000) or G (x1073741824)."
++      "MD (x1000000), M (x1048576), GD (x1000000000) or G (x1073741824)"
+ #define dd_example_usage \
+       "$ dd if=/dev/zero of=/dev/ram1 bs=1M count=4\n" \
+       "4+0 records in\n" \
+@@ -350,13 +384,13 @@
+        "Deletes user USER from the system"
+ #ifdef CONFIG_DEVFSD_FG_NP
+-  #define USAGE_DEVFSD_FG_NP(a) a
++#  define USAGE_DEVFSD_FG_NP(a) a
+ #else
+-  #define USAGE_DEVFSD_FG_NP(a)
++#  define USAGE_DEVFSD_FG_NP(a)
+ #endif
+ #define devfsd_trivial_usage \
+-      "mntpnt [-v]"\
++      "mntpnt [-v]" \
+       USAGE_DEVFSD_FG_NP("[-fg][-np]" )
+ #define devfsd_full_usage \
+       "Optional daemon for managing devfs permissions and old device name symlinks.\n" \
+@@ -370,11 +404,11 @@
+       "\t\tDo not poll for events.")
+ #ifdef CONFIG_FEATURE_HUMAN_READABLE
+-  #define USAGE_HUMAN_READABLE(a) a
+-  #define USAGE_NOT_HUMAN_READABLE(a)
++#  define USAGE_HUMAN_READABLE(a) a
++#  define USAGE_NOT_HUMAN_READABLE(a)
+ #else
+-  #define USAGE_HUMAN_READABLE(a)
+-  #define USAGE_NOT_HUMAN_READABLE(a) a
++#  define USAGE_HUMAN_READABLE(a)
++#  define USAGE_NOT_HUMAN_READABLE(a) a
+ #endif
+ #define df_trivial_usage \
+       "[-" USAGE_HUMAN_READABLE("hm") USAGE_NOT_HUMAN_READABLE("") "k] [FILESYSTEM ...]"
+@@ -508,9 +542,9 @@
+       "\t-a,\t--absolute\tInterpret lease times as expire time"
+ #ifdef CONFIG_FEATURE_FANCY_ECHO
+-  #define USAGE_FANCY_ECHO(a) a
++#  define USAGE_FANCY_ECHO(a) a
+ #else
+-  #define USAGE_FANCY_ECHO(a)
++#  define USAGE_FANCY_ECHO(a)
+ #endif
+ #define echo_trivial_usage \
+@@ -522,15 +556,22 @@
+       "\t-e\tinterpret backslash-escaped characters (i.e., \\t=tab)\n" \
+       "\t-E\tdisable interpretation of backslash-escaped characters")
+ #define echo_example_usage \
+-      "$ echo "Erik is cool"\n" \
++      "$ echo \"Erik is cool\"\n" \
+       "Erik is cool\n" \
+-      USAGE_FANCY_ECHO("$  echo -e "Erik\\nis\\ncool"\n" \
++      USAGE_FANCY_ECHO("$  echo -e \"Erik\\nis\\ncool\"\n" \
+       "Erik\n" \
+       "is\n" \
+       "cool\n" \
+-      "$ echo "Erik\\nis\\ncool"\n" \
++      "$ echo \"Erik\\nis\\ncool\"\n" \
+       "Erik\\nis\\ncool\n")
++#define eject_trivial_usage \
++      "[-t] [DEVICE]"
++#define eject_full_usage \
++      "Eject specified DEVICE (or default /dev/cdrom).\n\n" \
++      "Options:\n" \
++      "\t-t\tclose tray"
++
+ #define env_trivial_usage \
+       "[-iu] [-] [name=value]... [command]"
+ #define env_full_usage \
+@@ -540,6 +581,17 @@
+       "\t-, -i\tstart with an empty environment\n" \
+       "\t-u\tremove variable from the environment"
++#define ether_wake_trivial_usage \
++      "[-b] [-i iface] [-p aa:bb:cc:dd[:ee:ff]] MAC"
++#define ether_wake_full_usage \
++      "Send a magic packet to wake up sleeping machines.\n" \
++      "MAC must be a station address (00:11:22:33:44:55) or\n" \
++      "    a hostname with a known 'ethers' entry.\n\n" \
++      "Options:\n" \
++      "\t-b\t\tSend wake-up packet to the broadcast address\n" \
++      "\t-i iface\tUse interface ifname instead of the default \"eth0\"\n" \
++      "\t-p pass\tAppend the four or six byte password PW to the packet\n"
++
+ #define expr_trivial_usage \
+       "EXPRESSION"
+ #define expr_full_usage \
+@@ -574,6 +626,13 @@
+       "\\( and \\) or null; if \\( and \\) are not used, they return the number \n" \
+       "of characters matched or 0."
++#define fakeidentd_trivial_usage \
++      "[-b ip] [STRING]"
++#define fakeidentd_full_usage \
++      "Returns a set string to auth requests\n\n" \
++      "\t-b\tBind to ip address\n" \
++      "\tSTRING\tThe ident answer string (default is nobody)"
++
+ #define false_trivial_usage \
+       ""
+ #define false_full_usage \
+@@ -589,7 +648,7 @@
+       "Show and modify frame buffer settings"
+ #define fbset_example_usage \
+       "$ fbset\n" \
+-      "mode "1024x768-76"\n" \
++      "mode \"1024x768-76\"\n" \
+       "\t# D: 78.653 MHz, H: 59.949 kHz, V: 75.694 Hz\n" \
+       "\tgeometry 1024 768 1024 768 16\n" \
+       "\ttimings 12714 128 32 16 4 128 4\n" \
+@@ -624,29 +683,29 @@
+       "\t-v  Give fdisk version"
+ #ifdef CONFIG_FEATURE_FIND_TYPE
+-  #define USAGE_FIND_TYPE(a) a
++#  define USAGE_FIND_TYPE(a) a
+ #else
+-  #define USAGE_FIND_TYPE(a)
++#  define USAGE_FIND_TYPE(a)
+ #endif
+ #ifdef CONFIG_FEATURE_FIND_PERM
+-  #define USAGE_FIND_PERM(a) a
++#  define USAGE_FIND_PERM(a) a
+ #else
+-  #define USAGE_FIND_PERM(a)
++#  define USAGE_FIND_PERM(a)
+ #endif
+ #ifdef CONFIG_FEATURE_FIND_MTIME
+-  #define USAGE_FIND_MTIME(a) a
++#  define USAGE_FIND_MTIME(a) a
+ #else
+-  #define USAGE_FIND_MTIME(a)
++#  define USAGE_FIND_MTIME(a)
+ #endif
+ #ifdef CONFIG_FEATURE_FIND_NEWER
+-  #define USAGE_FIND_NEWER(a) a
++#  define USAGE_FIND_NEWER(a) a
+ #else
+-  #define USAGE_FIND_NEWER(a)
++#  define USAGE_FIND_NEWER(a)
+ #endif
+ #ifdef CONFIG_FEATURE_FIND_INUM
+-  #define USAGE_FIND_INUM(a) a
++#  define USAGE_FIND_INUM(a) a
+ #else
+-  #define USAGE_FIND_INUM(a)
++#  define USAGE_FIND_INUM(a)
+ #endif
+ #define find_trivial_usage \
+@@ -655,9 +714,9 @@
+       "Search for files in a directory hierarchy.  The default PATH is\n" \
+       "the current directory; default EXPRESSION is '-print'\n" \
+       "\nEXPRESSION may consist of:\n" \
+-      "\t-follow\t\tDereference symbolic links.\n" \
+-      "\t-name PATTERN\tFile name (leading directories removed) matches PATTERN.\n" \
+-      "\t-print\t\tPrint (default and assumed).\n" \
++      "\t-follow\t\tDereference symbolic links\n" \
++      "\t-name PATTERN\tFile name (leading directories removed) matches PATTERN\n" \
++      "\t-print\t\tPrint (default and assumed)\n" \
+       USAGE_FIND_TYPE( \
+       "\n\t-type X\t\tFiletype matches X (where X is one of: f,d,l,b,c,...)" \
+ ) USAGE_FIND_PERM( \
+@@ -711,7 +770,7 @@
+       "\t-v\tverbose\n" \
+       "\t-s\tOutputs super-block information\n" \
+       "\t-m\tActivates MINIX-like \"mode not cleared\" warnings\n" \
+-      "\t-f\tForce file system check."
++      "\t-f\tForce file system check"
+ #define ftpget_trivial_usage \
+       "[options] remote-host local-file remote-file"
+@@ -748,42 +807,42 @@
+       "\t-T, --test                   Test for getopt(1) version\n" \
+       "\t-u, --unquoted               Do not quote the output"
+ #define getopt_example_usage \
+-        "$ cat getopt.test\n" \
+-        "#!/bin/sh\n" \
+-        "GETOPT=`getopt -o ab:c:: --long a-long,b-long:,c-long:: \\\n" \
+-        "       -n 'example.busybox' -- "$@"`\n" \
+-        "if [ $? != 0 ] ; then  exit 1 ; fi\n" \
+-        "eval set -- "$GETOPT"\n" \
+-        "while true ; do\n" \
+-        " case $1 in\n" \
+-        "   -a|--a-long) echo \"Option a\" ; shift ;;\n" \
+-        "   -b|--b-long) echo \"Option b, argument `$2'\" ; shift 2 ;;\n" \
+-        "   -c|--c-long)\n" \
+-        "     case "$2" in\n" \
+-        "       \"\") echo \"Option c, no argument\"; shift 2 ;;\n" \
+-        "       *)  echo \"Option c, argument `$2'\" ; shift 2 ;;\n" \
+-        "     esac ;;\n" \
+-        "   --) shift ; break ;;\n" \
+-        "   *) echo \"Internal error!\" ; exit 1 ;;\n" \
+-        " esac\n" \
+-        "done\n"
++      "$ cat getopt.test\n" \
++      "#!/bin/sh\n" \
++      "GETOPT=`getopt -o ab:c:: --long a-long,b-long:,c-long:: \\\n" \
++      "       -n 'example.busybox' -- \"$@\"`\n" \
++      "if [ $? != 0 ] ; then  exit 1 ; fi\n" \
++      "eval set -- \"$GETOPT\"\n" \
++      "while true ; do\n" \
++      " case $1 in\n" \
++      "   -a|--a-long) echo \"Option a\" ; shift ;;\n" \
++      "   -b|--b-long) echo \"Option b, argument `$2'\" ; shift 2 ;;\n" \
++      "   -c|--c-long)\n" \
++      "     case \"$2\" in\n" \
++      "       \"\") echo \"Option c, no argument\"; shift 2 ;;\n" \
++      "       *)  echo \"Option c, argument `$2'\" ; shift 2 ;;\n" \
++      "     esac ;;\n" \
++      "   --) shift ; break ;;\n" \
++      "   *) echo \"Internal error!\" ; exit 1 ;;\n" \
++      " esac\n" \
++      "done\n"
+ #define getty_trivial_usage \
+       "[OPTIONS]... baud_rate,... line [termtype]"
+ #define getty_full_usage \
+       "Opens a tty, prompts for a login name, then invokes /bin/login\n\n" \
+       "Options:\n" \
+-      "\t-h\t\tEnable hardware (RTS/CTS) flow control.\n" \
+-      "\t-i\t\tDo not display /etc/issue before running login.\n" \
+-      "\t-L\t\tLocal line, so do not do carrier detect.\n" \
+-      "\t-m\t\tGet baud rate from modem's CONNECT status message.\n" \
+-      "\t-w\t\tWait for a CR or LF before sending /etc/issue.\n" \
+-      "\t-n\t\tDo not prompt the user for a login name.\n" \
+-      "\t-f issue_file\tDisplay issue_file instead of /etc/issue.\n" \
+-      "\t-l login_app\tInvoke login_app instead of /bin/login.\n" \
+-      "\t-t timeout\tTerminate after timeout if no username is read.\n" \
+-      "\t-I initstring\tSets the init string to send before anything else.\n" \
+-      "\t-H login_host\tLog login_host into the utmp file as the hostname."
++      "\t-h\t\tEnable hardware (RTS/CTS) flow control\n" \
++      "\t-i\t\tDo not display /etc/issue before running login\n" \
++      "\t-L\t\tLocal line, so do not do carrier detect\n" \
++      "\t-m\t\tGet baud rate from modem's CONNECT status message\n" \
++      "\t-w\t\tWait for a CR or LF before sending /etc/issue\n" \
++      "\t-n\t\tDo not prompt the user for a login name\n" \
++      "\t-f issue_file\tDisplay issue_file instead of /etc/issue\n" \
++      "\t-l login_app\tInvoke login_app instead of /bin/login\n" \
++      "\t-t timeout\tTerminate after timeout if no username is read\n" \
++      "\t-I initstring\tSets the init string to send before anything else\n" \
++      "\t-H login_host\tLog login_host into the utmp file as the hostname"
+ #define grep_trivial_usage \
+@@ -841,7 +900,7 @@
+ #define halt_full_usage \
+       "Halt the system.\n" \
+       "Options:\n" \
+-      "\t-d\t\tdelay interval for halting."
++      "\t-d\t\tdelay interval for halting"
+ #ifdef CONFIG_FEATURE_HDPARM_GET_IDENTITY
+ #define USAGE_HDPARM_IDENT(a) a
+@@ -951,7 +1010,7 @@
+       "[-[bcdefnosvx]] [OPTION] FILE"
+ #define hexdump_full_usage \
+       "The hexdump utility is a filter which displays the specified files,\n" \
+-      "or the standard input, if no files are specified, in a user specified\n"\
++      "or the standard input, if no files are specified, in a user specified\n" \
+       "format\n" \
+       "\t-b\t\tOne-byte octal display\n" \
+       "\t-c\t\tOne-byte character display\n" \
+@@ -985,26 +1044,26 @@
+       "sage\n"
+ #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH
+-  #define USAGE_HTTPD_BASIC_AUTH(a) a
+-  #ifdef CONFIG_FEATURE_HTTPD_AUTH_MD5
+-    #define USAGE_HTTPD_AUTH_MD5(a) a
+-  #else
+-    #define USAGE_HTTPD_AUTH_MD5(a)
+-  #endif
++#  define USAGE_HTTPD_BASIC_AUTH(a) a
++#  ifdef CONFIG_FEATURE_HTTPD_AUTH_MD5
++#    define USAGE_HTTPD_AUTH_MD5(a) a
++#  else
++#    define USAGE_HTTPD_AUTH_MD5(a)
++#  endif
+ #else
+-  #define USAGE_HTTPD_BASIC_AUTH(a)
+-  #define USAGE_HTTPD_AUTH_MD5(a)
++#  define USAGE_HTTPD_BASIC_AUTH(a)
++#  define USAGE_HTTPD_AUTH_MD5(a)
+ #endif
+ #ifdef CONFIG_FEATURE_HTTPD_USAGE_FROM_INETD_ONLY
+-  #define USAGE_HTTPD_STANDALONE(a)
+-  #define USAGE_HTTPD_SETUID(a)
++#  define USAGE_HTTPD_STANDALONE(a)
++#  define USAGE_HTTPD_SETUID(a)
+ #else
+-  #define USAGE_HTTPD_STANDALONE(a) a
+-  #ifdef CONFIG_FEATURE_HTTPD_SETUID
+-    #define USAGE_HTTPD_SETUID(a) a
+-  #else
+-    #define USAGE_HTTPD_SETUID(a)
+-  #endif
++#  define USAGE_HTTPD_STANDALONE(a) a
++#  ifdef CONFIG_FEATURE_HTTPD_SETUID
++#    define USAGE_HTTPD_SETUID(a) a
++#  else
++#    define USAGE_HTTPD_SETUID(a)
++#  endif
+ #endif
+ #define httpd_trivial_usage \
+       "[-c <conf file>]" \
+@@ -1015,16 +1074,16 @@
+       " [-h home]" \
+       " [-d/-e <string>]"
+ #define httpd_full_usage \
+-       "Listens for incoming http server requests.\n\n"\
+-       "Options:\n" \
+-       "\t-c FILE\t\tSpecifies configuration file. (default httpd.conf)\n" \
+-       USAGE_HTTPD_STANDALONE("\t-p PORT\tServer port (default 80)\n") \
+-       USAGE_HTTPD_SETUID("\t-u USER\tSet uid to USER after listening privileges port\n") \
+-       USAGE_HTTPD_BASIC_AUTH("\t-r REALM\tAuthentication Realm for Basic Authentication\n") \
+-       USAGE_HTTPD_AUTH_MD5("\t-m PASS\t\tCrypt PASS with md5 algorithm\n") \
+-       "\t-h HOME  \tSpecifies http HOME directory (default ./)\n" \
+-       "\t-e STRING\tHtml encode STRING\n" \
+-       "\t-d STRING\tURL decode STRING"
++      "Listens for incoming http server requests.\n\n" \
++      "Options:\n" \
++      "\t-c FILE\t\tSpecifies configuration file. (default httpd.conf)\n" \
++      USAGE_HTTPD_STANDALONE("\t-p PORT\tServer port (default 80)\n") \
++      USAGE_HTTPD_SETUID("\t-u USER\tSet uid to USER after listening privileges port\n") \
++      USAGE_HTTPD_BASIC_AUTH("\t-r REALM\tAuthentication Realm for Basic Authentication\n") \
++      USAGE_HTTPD_AUTH_MD5("\t-m PASS\t\tCrypt PASS with md5 algorithm\n") \
++      "\t-h HOME  \tSpecifies http HOME directory (default ./)\n" \
++      "\t-e STRING\tHtml encode STRING\n" \
++      "\t-d STRING\tURL decode STRING"
+ #define hwclock_trivial_usage \
+       "[-r|--show] [-s|--hctosys] [-w|--systohc] [-l|--localtime] [-u|--utc]"
+@@ -1038,9 +1097,9 @@
+       "\t-l\tthe hardware clock is kept in local time"
+ #ifdef CONFIG_SELINUX
+-  #define USAGE_SELINUX(a) a
++#  define USAGE_SELINUX(a) a
+ #else
+-  #define USAGE_SELINUX(a)
++#  define USAGE_SELINUX(a)
+ #endif
+ #define id_trivial_usage \
+@@ -1058,29 +1117,29 @@
+       "uid=1000(andersen) gid=1000(andersen)\n"
+ #ifdef CONFIG_FEATURE_IFCONFIG_SLIP
+-  #define USAGE_SIOCSKEEPALIVE(a) a
++#  define USAGE_SIOCSKEEPALIVE(a) a
+ #else
+-  #define USAGE_SIOCSKEEPALIVE(a)
++#  define USAGE_SIOCSKEEPALIVE(a)
+ #endif
+ #ifdef CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
+-  #define USAGE_IFCONFIG_MII(a) a
++#  define USAGE_IFCONFIG_MII(a) a
+ #else
+-  #define USAGE_IFCONFIG_MII(a)
++#  define USAGE_IFCONFIG_MII(a)
+ #endif
+ #ifdef CONFIG_FEATURE_IFCONFIG_HW
+-  #define USAGE_IFCONFIG_HW(a) a
++#  define USAGE_IFCONFIG_HW(a) a
+ #else
+-  #define USAGE_IFCONFIG_HW(a)
++#  define USAGE_IFCONFIG_HW(a)
+ #endif
+ #ifdef CONFIG_FEATURE_IFCONFIG_STATUS
+-  #define USAGE_IFCONFIG_OPT_A(a) a
++#  define USAGE_IFCONFIG_OPT_A(a) a
+ #else
+-  #define USAGE_IFCONFIG_OPT_A(a)
++#  define USAGE_IFCONFIG_OPT_A(a)
+ #endif
+ #ifdef CONFIG_FEATURE_IPV6
+-  #define USAGE_IPV6(a) a
++#  define USAGE_IPV6(a) a
+ #else
+-  #define USAGE_IPV6(a)
++#  define USAGE_IPV6(a)
+ #endif
+ #define ifconfig_trivial_usage \
+@@ -1094,7 +1153,7 @@
+       "\t[netmask <address>]  [dstaddr <address>]\n" \
+       USAGE_SIOCSKEEPALIVE("\t[outfill <NN>] [keepalive <NN>]\n") \
+       "\t" USAGE_IFCONFIG_HW("[hw ether <address>]  ") \
+-    "[metric <NN>]  [mtu <NN>]\n" \
++      "[metric <NN>]  [mtu <NN>]\n" \
+       "\t[[-]trailers]  [[-]arp]  [[-]allmulti]\n" \
+       "\t[multicast]  [[-]promisc]  [txqueuelen <NN>]  [[-]dynamic]\n" \
+       USAGE_IFCONFIG_MII("\t[mem_start <NN>]  [io_addr <NN>]  [irq <NN>]\n") \
+@@ -1134,7 +1193,7 @@
+       "Listens for network connections and launches programs\n\n" \
+       "Option:\n" \
+       "\t-q\tSets the size of the socket listen queue to\n" \
+-      "\t\tthe specified value. Default is 128."
++      "\t\tthe specified value. Default is 128"
+ #define init_trivial_usage \
+       ""
+@@ -1172,7 +1231,7 @@
+ "             WARNING: This field has a non-traditional meaning for BusyBox init!\n" \
+ "             The id field is used by BusyBox init to specify the controlling tty for\n" \
+ "             the specified process to run on.  The contents of this field are\n" \
+-"             appended to "/dev/" and used as-is.  There is no need for this field to\n" \
++"             appended to \"/dev/\" and used as-is.  There is no need for this field to\n" \
+ "             be unique, although if it isn't you may have strange results.  If this\n" \
+ "             field is left blank, the controlling tty is set to the console.  Also\n" \
+ "             note that if BusyBox detects that a serial console is in use, then only\n" \
+@@ -1218,7 +1277,7 @@
+ "                     it.  Unlike sysvinit, BusyBox init does not stop processes from\n" \
+ "                     respawning out of control.  The 'askfirst' actions acts just like\n" \
+ "                     respawn, except that before running the specified process it\n" \
+-"                     displays the line "Please press Enter to activate this console."\n" \
++"                     displays the line \"Please press Enter to activate this console.\"\n" \
+ "                     and then waits for the user to press enter before starting the\n" \
+ "                     specified process.\n" \
+ "\n" \
+@@ -1238,9 +1297,9 @@
+ "     \n" \
+ "     # /bin/sh invocations on selected ttys\n" \
+ "     #\n" \
+-"     # Start an "askfirst" shell on the console (whatever that may be)\n" \
++"     # Start an \"askfirst\" shell on the console (whatever that may be)\n" \
+ "     ::askfirst:-/bin/sh\n" \
+-"     # Start an "askfirst" shell on /dev/tty2-4\n" \
++"     # Start an \"askfirst\" shell on /dev/tty2-4\n" \
+ "     tty2::askfirst:-/bin/sh\n" \
+ "     tty3::askfirst:-/bin/sh\n" \
+ "     tty4::askfirst:-/bin/sh\n" \
+@@ -1268,17 +1327,17 @@
+ "     ::shutdown:/sbin/swapoff -a\n"
+ #ifdef CONFIG_FEATURE_INSMOD_LOAD_MAP
+-  #define USAGE_INSMOD_MAP(a) a
++#  define USAGE_INSMOD_MAP(a) a
+ #else
+-  #define USAGE_INSMOD_MAP(a)
++#  define USAGE_INSMOD_MAP(a)
+ #endif
+ #define insmod_trivial_usage \
+       "[OPTION]... MODULE [symbol=value]..."
+ #define insmod_full_usage \
+       "Loads the specified kernel modules into the kernel.\n\n" \
+       "Options:\n" \
+-      "\t-f\tForce module to load into the wrong kernel version.\n" \
+-      "\t-k\tMake module autoclean-able.\n" \
++      "\t-f\tForce module to load into the wrong kernel version\n" \
++      "\t-k\tMake module autoclean-able\n" \
+       "\t-v\tverbose output\n"  \
+       "\t-q\tquiet output\n" \
+       "\t-L\tLock to prevent simultaneous loads of a module\n" \
+@@ -1319,21 +1378,21 @@
+       "\t\t\tSCOPE-ID := [ host | link | global | NUMBER ]"
+ #ifdef CONFIG_FEATURE_IPCALC_FANCY
+-  #define XUSAGE_IPCALC_FANCY(a) a
++#  define XUSAGE_IPCALC_FANCY(a) a
+ #else
+-  #define XUSAGE_IPCALC_FANCY(a)
++#  define XUSAGE_IPCALC_FANCY(a)
+ #endif
+ #define ipcalc_trivial_usage \
+       "[OPTION]... <ADDRESS>[[/]<NETMASK>] [NETMASK]"
+ #define ipcalc_full_usage \
+       "Calculate IP network settings from a IP address\n\n" \
+       "Options:\n" \
+-      "\t-b\t--broadcast\tDisplay calculated broadcast address.\n" \
+-      "\t-n\t--network\tDisplay calculated network address.\n" \
++      "\t-b\t--broadcast\tDisplay calculated broadcast address\n" \
++      "\t-n\t--network\tDisplay calculated network address\n" \
+       "\t-m\t--netmask\tDisplay default netmask for IP." \
+-      XUSAGE_IPCALC_FANCY(\
++      XUSAGE_IPCALC_FANCY( \
+       "\n\t-p\t--prefix\tDisplay the prefix for IP/NETMASK." \
+-      "\t-h\t--hostname\tDisplay first resolved host name.\n" \
++      "\t-h\t--hostname\tDisplay first resolved host name\n" \
+       "\t-s\t--silent\tDon't ever display error messages.")
+ #define iplink_trivial_usage \
+@@ -1368,9 +1427,9 @@
+ #define kill_trivial_usage \
+       "[-signal] process-id [process-id ...]"
+ #define kill_full_usage \
+-      "Send a signal (default is SIGTERM) to the specified process(es).\n\n"\
++      "Send a signal (default is SIGTERM) to the specified process(es).\n\n" \
+       "Options:\n" \
+-      "\t-l\tList all signal names and numbers."
++      "\t-l\tList all signal names and numbers"
+ #define kill_example_usage \
+       "$ ps | grep apache\n" \
+       "252 root     root     S [apache]\n" \
+@@ -1384,20 +1443,20 @@
+ #define killall_trivial_usage \
+       "[-q] [-signal] process-name [process-name ...]"
+ #define killall_full_usage \
+-      "Send a signal (default is SIGTERM) to the specified process(es).\n\n"\
++      "Send a signal (default is SIGTERM) to the specified process(es).\n\n" \
+       "Options:\n" \
+-      "\t-l\tList all signal names and numbers.\n"\
+-      "\t-q\tDo not complain if no processes were killed."
++      "\t-l\tList all signal names and numbers\n" \
++      "\t-q\tDo not complain if no processes were killed"
+ #define killall_example_usage \
+       "$ killall apache\n"
+ #define klogd_trivial_usage \
+       "[-c n] [-n]"
+ #define klogd_full_usage \
+-      "Kernel logger.\n"\
+-      "Options:\n"\
+-      "\t-c n\tSets the default log level of console messages to n.\n"\
+-      "\t-n\tRun as a foreground process."
++      "Kernel logger.\n" \
++      "Options:\n" \
++      "\t-c n\tSets the default log level of console messages to n\n" \
++      "\t-n\tRun as a foreground process"
+ #define length_trivial_usage \
+       "STRING"
+@@ -1410,12 +1469,14 @@
+ #define ln_trivial_usage \
+       "[OPTION] TARGET... LINK_NAME|DIRECTORY"
+ #define ln_full_usage \
+-      "Create a link named LINK_NAME or DIRECTORY to the specified TARGET\n"\
++      "Create a link named LINK_NAME or DIRECTORY to the specified TARGET\n" \
+       "\nYou may use '--' to indicate that all following arguments are non-options.\n\n" \
+       "Options:\n" \
+       "\t-s\tmake symbolic links instead of hard links\n" \
+       "\t-f\tremove existing destination files\n" \
+-      "\t-n\tno dereference symlinks - treat like normal file"
++      "\t-n\tno dereference symlinks - treat like normal file\n" \
++      "\t-b\tmake a backup of the target (if exists) before link operation\n" \
++      "\t-S suffix\tuse suffix instead of ~ when making backup files"
+ #define ln_example_usage \
+       "$ ln -s BusyBox /tmp/ls\n" \
+       "$ ls -l /tmp/ls\n" \
+@@ -1440,12 +1501,12 @@
+ #define logger_full_usage \
+       "Write MESSAGE to the system log.  If MESSAGE is omitted, log stdin.\n\n" \
+       "Options:\n" \
+-      "\t-s\tLog to stderr as well as the system log.\n" \
+-      "\t-t TAG\tLog using the specified tag (defaults to user name).\n" \
+-      "\t-p PRIORITY\tEnter the message with the specified priority.\n" \
+-      "\t\tThis may be numerical or a ``facility.level'' pair."
++      "\t-s\tLog to stderr as well as the system log\n" \
++      "\t-t TAG\tLog using the specified tag (defaults to user name)\n" \
++      "\t-p PRIORITY\tEnter the message with the specified priority\n" \
++      "\t\tThis may be numerical or a ``facility.level'' pair"
+ #define logger_example_usage \
+-      "$ logger "hello"\n"
++      "$ logger \"hello\"\n"
+ #define login_trivial_usage \
+       "[OPTION]... [username] [ENV=VAR ...]"
+@@ -1453,8 +1514,8 @@
+       "Begin a new session on the system\n\n" \
+       "Options:\n" \
+       "\t-f\tDo not authenticate (user already authenticated)\n" \
+-      "\t-h\tName of the remote host for this login.\n" \
+-      "\t-p\tPreserve environment."
++      "\t-h\tName of the remote host for this login\n" \
++      "\t-p\tPreserve environment"
+ #define logname_trivial_usage \
+       ""
+@@ -1467,7 +1528,7 @@
+ #define logread_trivial_usage \
+       "[OPTION]..."
+ #define logread_full_usage \
+-        "Shows the messages from syslogd (using circular buffer).\n\n" \
++      "Shows the messages from syslogd (using circular buffer).\n\n" \
+       "Options:\n" \
+       "\t-f\t\toutput data as the log grows"
+@@ -1477,38 +1538,38 @@
+ #define losetup_full_usage \
+       "Associate LOOPDEVICE with FILE.\n\n" \
+       "Options:\n" \
+-      "\t-d\t\tDisassociate LOOPDEVICE.\n" \
+-      "\t-o OFFSET\tStart OFFSET bytes into FILE."
++      "\t-d\t\tDisassociate LOOPDEVICE\n" \
++      "\t-o OFFSET\tStart OFFSET bytes into FILE"
+ #ifdef CONFIG_FEATURE_LS_TIMESTAMPS
+-  #define USAGE_LS_TIMESTAMPS(a) a
++#  define USAGE_LS_TIMESTAMPS(a) a
+ #else
+-  #define USAGE_LS_TIMESTAMPS(a)
++#  define USAGE_LS_TIMESTAMPS(a)
+ #endif
+ #ifdef CONFIG_FEATURE_LS_FILETYPES
+-  #define USAGE_LS_FILETYPES(a) a
++#  define USAGE_LS_FILETYPES(a) a
+ #else
+-  #define USAGE_LS_FILETYPES(a)
++#  define USAGE_LS_FILETYPES(a)
+ #endif
+ #ifdef CONFIG_FEATURE_LS_FOLLOWLINKS
+-  #define USAGE_LS_FOLLOWLINKS(a) a
++#  define USAGE_LS_FOLLOWLINKS(a) a
+ #else
+-  #define USAGE_LS_FOLLOWLINKS(a)
++#  define USAGE_LS_FOLLOWLINKS(a)
+ #endif
+ #ifdef CONFIG_FEATURE_LS_RECURSIVE
+-  #define USAGE_LS_RECURSIVE(a) a
++#  define USAGE_LS_RECURSIVE(a) a
+ #else
+-  #define USAGE_LS_RECURSIVE(a)
++#  define USAGE_LS_RECURSIVE(a)
+ #endif
+ #ifdef CONFIG_FEATURE_LS_SORTFILES
+-  #define USAGE_LS_SORTFILES(a) a
++#  define USAGE_LS_SORTFILES(a) a
+ #else
+-  #define USAGE_LS_SORTFILES(a)
++#  define USAGE_LS_SORTFILES(a)
+ #endif
+ #ifdef CONFIG_FEATURE_AUTOWIDTH
+-  #define USAGE_AUTOWIDTH(a) a
++#  define USAGE_AUTOWIDTH(a) a
+ #else
+-  #define USAGE_AUTOWIDTH(a)
++#  define USAGE_AUTOWIDTH(a)
+ #endif
+ #define ls_trivial_usage \
+@@ -1545,6 +1606,17 @@
+       USAGE_SELINUX("\t-k\tprint security context\n") \
+       USAGE_SELINUX("\t-K\tprint security context in long format\n")
++#define lsattr_trivial_usage \
++      "[-Radlv] [files...]"
++#define lsattr_full_usage \
++      "list file attributes on an ext2 fs\n\n" \
++      "Options:\n" \
++      "\t-R\trecursively list subdirectories\n" \
++      "\t-a\tdo not hide entries starting with .\n" \
++      "\t-d\tlist directory entries instead of contents\n" \
++      "\t-l\tprint long flag names\n" \
++      "\t-v\tlist the file's version/generation number"
++
+ #define lsmod_trivial_usage \
+       ""
+ #define lsmod_full_usage \
+@@ -1559,7 +1631,7 @@
+       "\tc or u:\tMake a character (un-buffered) device.\n" \
+       "\tp:\tMake a named pipe. MAJOR and MINOR are ignored for named pipes.\n\n" \
+       "FIRST specifies the number appended to NAME to create the first device.\n" \
+-      "LAST specifies the number of the last item that should be created.\n" \
++      "LAST specifies the number of the last item that should be created\n" \
+       "If 's' is the last argument, the base device is created as well.\n\n" \
+       "For example:\n" \
+       "\tmakedevs /dev/ttyS c 4 66 2 63   ->  ttyS2-ttyS63\n" \
+@@ -1602,8 +1674,8 @@
+       "[y|n]"
+ #define mesg_full_usage \
+       "mesg controls write access to your terminal\n" \
+-      "\ty\tAllow write access to your terminal.\n" \
+-      "\tn\tDisallow write access to your terminal.\n"
++      "\ty\tAllow write access to your terminal\n" \
++      "\tn\tDisallow write access to your terminal"
+ #define mkdir_trivial_usage \
+       "[OPTION] DIRECTORY..."
+@@ -1645,9 +1717,9 @@
+       "Options:\n" \
+       "\t-m\tcreate the special file using the specified mode (default a=rw)\n\n" \
+       "TYPEs include:\n" \
+-      "\tb:\tMake a block (buffered) device.\n" \
+-      "\tc or u:\tMake a character (un-buffered) device.\n" \
+-      "\tp:\tMake a named pipe. MAJOR and MINOR are ignored for named pipes."
++      "\tb:\tMake a block (buffered) device\n" \
++      "\tc or u:\tMake a character (un-buffered) device\n" \
++      "\tp:\tMake a named pipe. MAJOR and MINOR are ignored for named pipes"
+ #define mknod_example_usage \
+       "$ mknod /dev/fd0 b 2 0\n" \
+       "$ mknod -m 644 /tmp/pipe p\n"
+@@ -1657,10 +1729,10 @@
+ #define mkswap_full_usage \
+       "Prepare a disk partition to be used as a swap partition.\n\n" \
+       "Options:\n" \
+-      "\t-c\t\tCheck for read-ability.\n" \
+-      "\t-v0\t\tMake version 0 swap [max 128 Megs].\n" \
+-      "\t-v1\t\tMake version 1 swap [big!] (default for kernels >\n\t\t\t2.1.117).\n" \
+-      "\tblock-count\tNumber of block to use (default is entire partition)."
++      "\t-c\t\tCheck for read-ability\n" \
++      "\t-v0\t\tMake version 0 swap [max 128 Megs]\n" \
++      "\t-v1\t\tMake version 1 swap [big!] (default for kernels >\n\t\t\t2.1.117)\n" \
++      "\tblock-count\tNumber of block to use (default is entire partition)"
+ #define mktemp_trivial_usage \
+       "[-dq] TEMPLATE"
+@@ -1681,12 +1753,12 @@
+ #define modprobe_full_usage \
+       "Used for high level module loading and unloading.\n\n" \
+       "Options:\n" \
+-      "\t-k\tMake module autoclean-able.\n" \
+-      "\t-n\tJust show what would be done.\n" \
+-      "\t-q\tQuiet output.\n" \
+-      "\t-r\tRemove module (stacks) or do autoclean.\n" \
+-      "\t-s\tReport via syslog instead of stderr.\n" \
+-      "\t-v\tVerbose output."
++      "\t-k\tMake module autoclean-able\n" \
++      "\t-n\tJust show what would be done\n" \
++      "\t-q\tQuiet output\n" \
++      "\t-r\tRemove module (stacks) or do autoclean\n" \
++      "\t-s\tReport via syslog instead of stderr\n" \
++      "\t-v\tVerbose output"
+ #define modprobe_example_usage \
+       "$ modprobe cdrom\n"
+@@ -1698,14 +1770,14 @@
+       "$ dmesg | more\n"
+ #ifdef CONFIG_FEATURE_MOUNT_LOOP
+-  #define USAGE_MOUNT_LOOP(a) a
++#  define USAGE_MOUNT_LOOP(a) a
+ #else
+-  #define USAGE_MOUNT_LOOP(a)
++#  define USAGE_MOUNT_LOOP(a)
+ #endif
+ #ifdef CONFIG_FEATURE_MTAB_SUPPORT
+-  #define USAGE_MTAB(a) a
++#  define USAGE_MTAB(a) a
+ #else
+-  #define USAGE_MTAB(a)
++#  define USAGE_MTAB(a)
+ #endif
+ #define mount_trivial_usage \
+       "[flags] DEVICE NODE [-o options,more-options]"
+@@ -1713,30 +1785,30 @@
+       "Mount a filesystem.  Autodetection of filesystem type requires the\n" \
+       "/proc filesystem be already mounted.\n\n" \
+       "Flags:\n"  \
+-      "\t-a:\t\tMount all filesystems in fstab.\n" \
++      "\t-a:\t\tMount all filesystems in fstab\n" \
+       USAGE_MTAB( \
+-      "\t-f:\t\t\"Fake\" Add entry to mount table but don't mount it.\n" \
+-      "\t-n:\t\tDon't write a mount table entry.\n" \
++      "\t-f:\t\t\"Fake\" Add entry to mount table but don't mount it\n" \
++      "\t-n:\t\tDon't write a mount table entry\n" \
+       ) \
+-      "\t-o option:\tOne of many filesystem options, listed below.\n" \
+-      "\t-r:\t\tMount the filesystem read-only.\n" \
+-      "\t-t fs-type:\tSpecify the filesystem type.\n" \
+-      "\t-w:\t\tMount for reading and writing (default).\n" \
++      "\t-o option:\tOne of many filesystem options, listed below\n" \
++      "\t-r:\t\tMount the filesystem read-only\n" \
++      "\t-t fs-type:\tSpecify the filesystem type\n" \
++      "\t-w:\t\tMount for reading and writing (default)\n" \
+       "\n" \
+       "Options for use with the \"-o\" flag:\n" \
+-      "\tasync/sync:\tWrites are asynchronous / synchronous.\n" \
+-      "\tatime/noatime:\tEnable / disable updates to inode access times.\n" \
+-      "\tdev/nodev:\tAllow use of special device files / disallow them.\n" \
+-      "\texec/noexec:\tAllow use of executable files / disallow them.\n" \
++      "\tasync/sync:\tWrites are asynchronous / synchronous\n" \
++      "\tatime/noatime:\tEnable / disable updates to inode access times\n" \
++      "\tdev/nodev:\tAllow use of special device files / disallow them\n" \
++      "\texec/noexec:\tAllow use of executable files / disallow them\n" \
+       USAGE_MOUNT_LOOP( \
+-      "\tloop:\t\tMounts a file via loop device.\n" \
++      "\tloop:\t\tMounts a file via loop device\n" \
+       ) \
+-      "\tsuid/nosuid:\tAllow set-user-id-root programs / disallow them.\n" \
+-      "\tremount:\tRe-mount a mounted filesystem, changing its flags.\n" \
+-      "\tro/rw:\t\tMount for read-only / read-write.\n" \
+-      "\tbind:\t\tUse the linux 2.4.x \"bind\" feature.\n" \
+-      "\nThere are EVEN MORE flags that are specific to each filesystem.\n" \
+-      "You'll have to see the written documentation for those filesystems."
++      "\tsuid/nosuid:\tAllow set-user-id-root programs / disallow them\n" \
++      "\tremount:\tRe-mount a mounted filesystem, changing its flags\n" \
++      "\tro/rw:\t\tMount for read-only / read-write\n" \
++      "\tbind:\t\tUse the linux 2.4.x \"bind\" feature\n" \
++      "\nThere are EVEN MORE flags that are specific to each filesystem\n" \
++      "You'll have to see the written documentation for those filesystems"
+ #define mount_example_usage \
+       "$ mount\n" \
+       "/dev/hda3 on / type minix (rw)\n" \
+@@ -1772,13 +1844,18 @@
+       "Nameif renaming network interface while it in the down state.\n\n" \
+       "Options:\n" \
+       "\t-c FILE\t\tUse configuration file (default is /etc/mactab)\n" \
+-      "\t-s\t\tUse syslog (LOCAL0 facility).\n" \
++      "\t-s\t\tUse syslog (LOCAL0 facility)\n" \
+       "\tIFNAME MACADDR\tnew_interface_name interface_mac_address"
+ #define nameif_example_usage \
+       "$ nameif -s dmz0 00:A0:C9:8C:F6:3F\n" \
+       " or\n" \
+       "$ nameif -c /etc/my_mactab_file\n" \
++#ifdef CONFIG_NC_GAPING_SECURITY_HOLE
++#  define USAGE_NC_EXEC(a) a
++#else
++#  define USAGE_NC_EXEC(a)
++#endif
+ #define nc_trivial_usage \
+       "[OPTIONS] [IP] [port]"
+ #define nc_full_usage \
+@@ -1787,7 +1864,10 @@
+       "\t-l\t\tlisten mode, for inbound connects\n" \
+       "\t-p PORT\t\tlocal port number\n" \
+       "\t-i SECS\t\tdelay interval for lines sent\n" \
+-      "\t-e PROG\t\tprogram to exec after connect (dangerous!)"
++      USAGE_NC_EXEC( \
++      "\t-e PROG\t\tprogram to exec after connect (dangerous!)\n" \
++      ) \
++      "\t-w SECS\t\ttimeout for connects and final net reads"
+ #define nc_example_usage \
+       "$ nc foobar.somedomain.com 25\n" \
+       "220 foobar ESMTP Exim 3.12 #1 Sat, 15 Apr 2000 00:03:02 -0600\n" \
+@@ -1813,6 +1893,13 @@
+       "\t-w raw sockets\n" \
+       "\t-x unix sockets"
++#define nice_trivial_usage \
++      "[-n ADJUST] [COMMAND [ARG] ...]"
++#define nice_full_usage \
++      "Nice runs a program with modified scheduling priority.\n\n" \
++      "Options:\n" \
++      "\t-n ADJUST\tAdjust the scheduling priority by ADJUST"
++
+ #define nslookup_trivial_usage \
+       "[HOST] [SERVER]"
+ #define nslookup_full_usage \
+@@ -1829,7 +1916,7 @@
+ #define od_trivial_usage \
+       "[-aBbcDdeFfHhIiLlOovXx] [FILE]"
+ #define od_full_usage \
+-      "Write an unambiguous representation, octal bytes by default, of FILE\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."
+ #define openvt_trivial_usage \
+@@ -1840,9 +1927,9 @@
+       "openvt 2 /bin/ash\n"
+ #ifdef CONFIG_FEATURE_SHA1_PASSWORDS
+-  #define PASSWORD_ALG_TYPES(a) a
++#  define PASSWORD_ALG_TYPES(a) a
+ #else
+-  #define PASSWORD_ALG_TYPES(a)
++#  define PASSWORD_ALG_TYPES(a)
+ #endif
+ #define passwd_trivial_usage \
+       "[OPTION] [name]"
+@@ -1850,12 +1937,12 @@
+       "Change a user password. If no name is specified,\n" \
+       "changes the password for the current user.\n" \
+       "Options:\n" \
+-      "\t-a\tDefine which algorithm shall be used for the password.\n" \
++      "\t-a\tDefine which algorithm shall be used for the password\n" \
+       "\t\t\t(Choices: des, md5" \
+       PASSWORD_ALG_TYPES(", sha1") \
+-      ")\n\t-d\tDelete the password for the specified user account.\n" \
+-      "\t-l\tLocks (disables) the specified user account.\n" \
+-      "\t-u\tUnlocks (re-enables) the specified user account."
++      ")\n\t-d\tDelete the password for the specified user account\n" \
++      "\t-l\tLocks (disables) the specified user account\n" \
++      "\t-u\tUnlocks (re-enables) the specified user account"
+ #define patch_trivial_usage \
+       "[-p<num>]"
+@@ -1870,7 +1957,7 @@
+       "Lists the PIDs of all processes with names that match the\n" \
+       "names on the command line.\n" \
+       "Options:\n" \
+-      "\t-s\t\tdisplay only a single PID."
++      "\t-s\t\tdisplay only a single PID"
+ #define pidof_example_usage \
+       "$ pidof init\n" \
+       "1\n"
+@@ -1884,10 +1971,10 @@
+ #define ping_full_usage \
+       "Send ICMP ECHO_REQUEST packets to network hosts.\n\n" \
+       "Options:\n" \
+-      "\t-c COUNT\tSend only COUNT pings.\n" \
+-      "\t-s SIZE\t\tSend SIZE data bytes in packets (default=56).\n" \
++      "\t-c COUNT\tSend only COUNT pings\n" \
++      "\t-s SIZE\t\tSend SIZE data bytes in packets (default=56)\n" \
+       "\t-q\t\tQuiet mode, only displays output at start\n" \
+-      "\t\t\tand when finished."
++      "\t\t\tand when finished"
+ #endif
+ #define ping_example_usage \
+       "$ ping localhost\n" \
+@@ -1907,10 +1994,10 @@
+ #define ping6_full_usage \
+       "Send ICMP ECHO_REQUEST packets to network hosts.\n\n" \
+       "Options:\n" \
+-      "\t-c COUNT\tSend only COUNT pings.\n" \
+-      "\t-s SIZE\t\tSend SIZE data bytes in packets (default=56).\n" \
++      "\t-c COUNT\tSend only COUNT pings\n" \
++      "\t-s SIZE\t\tSend SIZE data bytes in packets (default=56)\n" \
+       "\t-q\t\tQuiet mode, only displays output at start\n" \
+-      "\t\t\tand when finished."
++      "\t\t\tand when finished"
+ #endif
+ #define ping6_example_usage \
+       "$ ping6 ip6-localhost\n" \
+@@ -1932,7 +2019,13 @@
+ #define poweroff_full_usage \
+       "Halt the system and request that the kernel shut off the power.\n" \
+       "Options:\n" \
+-      "\t-d\t\tdelay interval for shutting off."
++      "\t-d\t\tdelay interval for shutting off"
++
++#define printenv_trivial_usage \
++      "[VARIABLES...]"
++#define printenv_full_usage \
++      "print all or part of environment\n\n" \
++      "If no environment VARIABLE specified, print them all."
+ #define printf_trivial_usage \
+       "FORMAT [ARGUMENT...]"
+@@ -1940,7 +2033,7 @@
+       "Formats and prints ARGUMENT(s) according to FORMAT,\n" \
+       "Where FORMAT controls the output exactly as in C printf."
+ #define printf_example_usage \
+-      "$ printf "Val=%d\\n" 5\n" \
++      "$ printf \"Val=%d\\n\" 5\n" \
+       "Val=5\n"
+ #ifdef CONFIG_SELINUX
+@@ -1982,13 +2075,36 @@
+ #define rdate_full_usage \
+       "Get and possibly set the system date and time from a remote HOST.\n\n" \
+       "Options:\n" \
+-      "\t-s\tSet the system date and time (default).\n" \
+-      "\t-p\tPrint the date and time."
++      "\t-s\tSet the system date and time (default)\n" \
++      "\t-p\tPrint the date and time"
++
++#ifdef CONFIG_FEATURE_READLINK_FOLLOW
++#define USAGE_READLINK_FOLLOW(a) a
++#else
++#define USAGE_READLINK_FOLLOW(a)
++#endif
+ #define readlink_trivial_usage \
+-      ""
++      USAGE_READLINK_FOLLOW("[-f] ") "FILE"
+ #define readlink_full_usage \
+-      "Displays the value of a symbolic link."
++      "Displays the value of a symbolic link." \
++      USAGE_READLINK_FOLLOW("\n\nOptions:\n" \
++      "\t-f\tcanonicalize by following all symlinks")
++
++#define readprofile_trivial_usage \
++      "[OPTIONS]..."
++#define readprofile_full_usage \
++      "Options:\n" \
++      "\t -m <mapfile>  (default: /boot/System.map)\n" \
++      "\t -p <profile>  (default: /proc/profile)\n" \
++      "\t -M <mult>     set the profiling multiplier to <mult>\n" \
++      "\t -i            print only info about the sampling step\n" \
++      "\t -v            print verbose data\n" \
++      "\t -a            print all symbols, even if count is 0\n" \
++      "\t -b            print individual histogram-bin counts\n" \
++      "\t -s            print individual counters within functions\n" \
++      "\t -r            reset all the counters (root only)\n" \
++      "\t -n            disable byte order auto-detection"
+ #define realpath_trivial_usage \
+       "pathname  ..."
+@@ -2000,14 +2116,17 @@
+ #define reboot_full_usage \
+       "Reboot the system.\n" \
+       "Options:\n" \
+-      "\t-d\t\tdelay interval for rebooting."
++      "\t-d\t\tdelay interval for rebooting"
+ #define renice_trivial_usage \
+-      "priority pid [pid ...]"
++      "{{-n INCREMENT} | PRIORITY} [[ -p | -g | -u ] ID ...]"
+ #define renice_full_usage \
+-      "Changes priority of running processes. Allowed priorities range\n" \
+-      "from 20 (the process runs only when nothing else is running) to 0\n" \
+-      "(default priority) to -20 (almost nothing else ever gets to run)."
++      "Changes priority of running processes.\n\n" \
++      "Options:\n" \
++      "\t-n\tadjusts current nice value (smaller is faster)\n" \
++      "\t-p\tprocess id(s) (default)\n" \
++      "\t-g\tprocess group id(s)\n" \
++      "\t-u\tprocess user name(s) and/or id(s)"
+ #define reset_trivial_usage \
+       ""
+@@ -2043,9 +2162,9 @@
+       "$ rmmod tulip\n"
+ #ifdef CONFIG_FEATURE_IPV6
+-  #define USAGE_ROUTE_IPV6(a) a
++#  define USAGE_ROUTE_IPV6(a) a
+ #else
+-  #define USAGE_ROUTE_IPV6(a) "\t"
++#  define USAGE_ROUTE_IPV6(a) "\t"
+ #endif
+@@ -2054,9 +2173,9 @@
+ #define route_full_usage \
+       "Edit the kernel's routing tables.\n\n" \
+       "Options:\n" \
+-      "\t-n\t\tDont resolve names.\n" \
+-      "\t-e\t\tDisplay other/more information.\n" \
+-      "\t-A inet" USAGE_ROUTE_IPV6("{6}") "\tSelect address family."
++      "\t-n\t\tDont resolve names\n" \
++      "\t-e\t\tDisplay other/more information\n" \
++      "\t-A inet" USAGE_ROUTE_IPV6("{6}") "\tSelect address family"
+ #define rpm_trivial_usage \
+       "-i -q[ildc]p package.rpm"
+@@ -2081,9 +2200,9 @@
+ #define run_parts_full_usage \
+       "Run a bunch of scripts in a directory.\n\n" \
+       "Options:\n" \
+-      "\t-t\tPrints what would be run, but does not actually run anything.\n" \
+-      "\t-a ARG\tPass ARG as an argument for every program invoked.\n" \
+-      "\t-u MASK\tSet the umask to MASK before executing every program."
++      "\t-t\tPrints what would be run, but does not actually run anything\n" \
++      "\t-a ARG\tPass ARG as an argument for every program invoked\n" \
++      "\t-u MASK\tSet the umask to MASK before executing every program"
+ #define rx_trivial_usage \
+       "FILE"
+@@ -2098,18 +2217,18 @@
+       "Options:\n" \
+       "\t-e script\tadd the script to the commands to be executed\n" \
+       "\t-f scriptfile\tadd script-file contents to the\n" \
+-          "\t\t\tcommands to be executed\n" \
++      "\t\t\tcommands to be executed\n" \
+       "\t-i\t\tedit files in-place\n" \
+       "\t-n\t\tsuppress automatic printing of pattern space\n" \
+       "\t-r\t\tuse extended regular expression syntax\n" \
+       "\n" \
+-      "If no -e or -f is given, the first non-option argument is taken as the sed\n"\
+-      "script to interpret. All remaining arguments are names of input files; if no\n"\
++      "If no -e or -f is given, the first non-option argument is taken as the sed\n" \
++      "script to interpret. All remaining arguments are names of input files; if no\n" \
+       "input files are specified, then the standard input is read.  Source files\n" \
+       "will not be modified unless -i option is given."
+ #define sed_example_usage \
+-      "$ echo "foo" | sed -e 's/f[a-zA-Z]o/bar/g'\n" \
++      "$ echo \"foo\" | sed -e 's/f[a-zA-Z]o/bar/g'\n" \
+       "bar\n"
+ #define seq_trivial_usage \
+@@ -2142,7 +2261,7 @@
+       "Use lash just as you would use any other shell.  It properly handles pipes,\n" \
+       "redirects, job control, can be used as the shell for scripts, and has a\n" \
+       "sufficient set of builtins to do what is needed.  It does not (yet) support\n" \
+-      "Bourne Shell syntax.  If you need things like "if-then-else", "while", and such\n" \
++      "Bourne Shell syntax.  If you need things like \"if-then-else\", \"while\", and such\n" \
+       "use ash or bash.  If you just need a very simple and extremely small shell,\n" \
+       "this will do the job."
+@@ -2165,11 +2284,11 @@
+       "\t-w\twarn about improperly formated SHA1 checksum lines")
+ #ifdef CONFIG_FEATURE_FANCY_SLEEP
+-  #define USAGE_FANCY_SLEEP(a) a
+-  #define USAGE_NOT_FANCY_SLEEP(a)
++#  define USAGE_FANCY_SLEEP(a) a
++#  define USAGE_NOT_FANCY_SLEEP(a)
+ #else
+-  #define USAGE_FANCY_SLEEP(a)
+-  #define USAGE_NOT_FANCY_SLEEP(a) a
++#  define USAGE_FANCY_SLEEP(a)
++#  define USAGE_NOT_FANCY_SLEEP(a) a
+ #endif
+ #define sleep_trivial_usage \
+@@ -2185,24 +2304,39 @@
+       USAGE_FANCY_SLEEP("$ sleep 1d 3h 22m 8s\n" \
+       "[98528 second delay results]\n")
+-#ifdef CONFIG_FEATURE_SORT_UNIQUE
+-  #define USAGE_SORT_UNIQUE(a) a
+-#else
+-  #define USAGE_SORT_UNIQUE(a)
+-#endif
+-#ifdef CONFIG_FEATURE_SORT_REVERSE
+-  #define USAGE_SORT_REVERSE(a) a
++#ifdef CONFIG_SORT_BIG
++#  define USAGE_SORT_BIG(a) a
+ #else
+-  #define USAGE_SORT_REVERSE(a)
++#  define USAGE_SORT_BIG(a)
+ #endif
++
+ #define sort_trivial_usage \
+-      "[-n" USAGE_SORT_REVERSE("r") USAGE_SORT_UNIQUE("u") "] [FILE]..."
++      "[-nru" USAGE_SORT_BIG("gMcszbdfimSTokt] [-o outfile] [-k start[.offset][opts][,end[.offset][opts]] [-t char") "] [FILE]..."
+ #define sort_full_usage \
+-      "Sorts lines of text in the specified files\n\n"\
++      "Sorts lines of text in the specified files\n\n" \
+       "Options:\n" \
+-      USAGE_SORT_UNIQUE("\t-u\tsuppress duplicate lines\n") \
+-      USAGE_SORT_REVERSE("\t-r\tsort in reverse order\n") \
+-      "\t-n\tsort numerics"
++      USAGE_SORT_BIG( \
++              "\t-b\tignore leading blanks\n" \
++              "\t-c\tcheck whether input is sorted\n" \
++              "\t-d\tdictionary order (blank or alphanumeric only)\n" \
++              "\t-f\tignore case\n" \
++              "\t-g\tgeneral numerical sort\n" \
++              "\t-i\tignore unprintable characters\n" \
++              "\t-k\tspecify sort key\n" \
++              "\t-M\tsort month\n" \
++      ) \
++      "\t-n\tsort numbers\n" \
++      USAGE_SORT_BIG( \
++              "\t-o\toutput to file\n" \
++              "\t-k\tsort by key\n" \
++              "\t-t\tuse key separator other than whitespace\n" \
++      ) \
++      "\t-r\treverse sort order\n" \
++      USAGE_SORT_BIG("\t-s\tstable (don't sort ties alphabetically)\n") \
++      "\t-u\tsuppress duplicate lines" \
++      USAGE_SORT_BIG("\n\t-z\tinput terminated by nulls, not newlines\n") \
++      USAGE_SORT_BIG("\t-mST\tignored for GNU compatability") \
++      ""
+ #define sort_example_usage \
+       "$ echo -e \"e\\nf\\nb\\nd\\nc\\na\" | sort\n" \
+       "a\n" \
+@@ -2210,34 +2344,98 @@
+       "c\n" \
+       "d\n" \
+       "e\n" \
+-      "f\n"
++      "f\n" \
++      USAGE_SORT_BIG( \
++              "$ echo -e \"c 3\\nb 2\\nd 2\" | $SORT -k 2,2n -k 1,1r\n" \
++              "d 2\n" \
++              "b 2\n" \
++              "c 3\n" \
++      ) \
++      ""
+ #define start_stop_daemon_trivial_usage \
+-      "[OPTIONS] [--start|--stop] ... [-- arguments...]\n"
++      "[OPTIONS] [--start|--stop] ... [-- arguments...]"
+ #define start_stop_daemon_full_usage \
+-      "Program to start and stop services."\
+-      "\n\nOptions:"\
+-      "\n\t-S|--start\t\t\tstart"\
+-      "\n\t-K|--stop\t\t\tstop"\
+-      "\n\t-a|--startas <pathname>\t\tstarts process specified by pathname"\
+-      "\n\t-b|--background\t\t\tforce process into background"\
+-      "\n\t-u|--user <username>|<uid>\tstop this user's processes"\
+-      "\n\t-x|--exec <executable>\t\tprogram to either start or check"\
+-      "\n\t-m|--make-pidfile <filename>\tcreate the -p file and enter pid in it"\
+-      "\n\t-n|--name <process-name>\tstop processes with this name"\
+-      "\n\t-p|--pidfile <pid-file>\t\tsave or load pid using a pid-file"\
++      "Program to start and stop services." \
++      "\n\nOptions:" \
++      "\n\t-S|--start\t\t\tstart" \
++      "\n\t-K|--stop\t\t\tstop" \
++      "\n\t-a|--startas <pathname>\t\tstarts process specified by pathname" \
++      "\n\t-b|--background\t\t\tforce process into background" \
++      "\n\t-u|--user <username>|<uid>\tstop this user's processes" \
++      "\n\t-x|--exec <executable>\t\tprogram to either start or check" \
++      "\n\t-m|--make-pidfile <filename>\tcreate the -p file and enter pid in it" \
++      "\n\t-n|--name <process-name>\tstop processes with this name" \
++      "\n\t-p|--pidfile <pid-file>\t\tsave or load pid using a pid-file" \
+       "\n\t-q|--quiet\t\t\tbe quiet" \
+       "\n\t-s|--signal <signal>\t\tsignal to send (default TERM)"
++#ifdef CONFIG_FEATURE_STAT_FORMAT
++#  define USAGE_STAT_FORMAT(a) a
++#else
++#  define USAGE_STAT_FORMAT(a)
++#endif
++#define stat_trivial_usage \
++      "[OPTION] FILE..."
++#define stat_full_usage \
++      "display file (default) or filesystem status.\n\n" \
++      "Options:\n" \
++      USAGE_STAT_FORMAT("\t-c fmt\tuse the specified format\n") \
++      "\t-f\tdisplay filesystem status\n" \
++      "\t-L,-l\tdereference links\n" \
++      "\t-t\tdisplay info in terse form\n" \
++      USAGE_STAT_FORMAT( \
++      "\nValid format sequences for files:\n" \
++      "  %a   Access rights in octal\n" \
++      "  %A   Access rights in human readable form\n" \
++      "  %b   Number of blocks allocated (see %B)\n" \
++      "  %B   The size in bytes of each block reported by %b\n" \
++      "  %d   Device number in decimal\n" \
++      "  %D   Device number in hex\n" \
++      "  %f   Raw mode in hex\n" \
++      "  %F   File type\n" \
++      "  %g   Group ID of owner\n" \
++      "  %G   Group name of owner\n" \
++      "  %h   Number of hard links\n" \
++      "  %i   Inode number\n" \
++      "  %n   File name\n" \
++      "  %N   Quoted file name with dereference if symbolic link\n" \
++      "  %o   I/O block size\n" \
++      "  %s   Total size, in bytes\n" \
++      "  %t   Major device type in hex\n" \
++      "  %T   Minor device type in hex\n" \
++      "  %u   User ID of owner\n" \
++      "  %U   User name of owner\n" \
++      "  %x   Time of last access\n" \
++      "  %X   Time of last access as seconds since Epoch\n" \
++      "  %y   Time of last modification\n" \
++      "  %Y   Time of last modification as seconds since Epoch\n" \
++      "  %z   Time of last change\n" \
++      "  %Z   Time of last change as seconds since Epoch\n" \
++      "\nValid format sequences for file systems:\n" \
++      "  %a   Free blocks available to non-superuser\n" \
++      "  %b   Total data blocks in file system\n" \
++      "  %c   Total file nodes in file system\n" \
++      "  %d   Free file nodes in file system\n" \
++      "  %f   Free blocks in file system\n" \
++      "  %i   File System ID in hex\n" \
++      "  %l   Maximum length of filenames\n" \
++      "  %n   File name\n" \
++      "  %s   Block size (for faster transfers)\n" \
++      "  %S   Fundamental block size (for block counts)\n" \
++      "  %t   Type in hex\n" \
++      "  %T   Type in human readable form\n" \
++      )
++
+ #define strings_trivial_usage \
+       "[-afo] [-n length] [file ... ]"
+ #define strings_full_usage \
+       "Display printable strings in a binary file." \
+       "\n\nOptions:" \
+-      "\n\t-a\tScan the whole files (this is the default)."\
++      "\n\t-a\tScan the whole files (this is the default)." \
+       "\n\t-f\tPrecede each string with the name of the file where it was found." \
+       "\n\t-n N\tSpecifies that at least N characters forms a sequence (default 4)" \
+-      "\n\t-o\tEach string is preceded by its decimal offset in the file."
++      "\n\t-o\tEach string is preceded by its decimal offset in the file"
+ #define stty_trivial_usage \
+       "[-a|g] [-F DEVICE] [SETTING]..."
+@@ -2263,8 +2461,16 @@
+       "Single user login\n" \
+       "Options:\n" \
+       "\t-f\tDo not authenticate (user already authenticated)\n" \
+-      "\t-h\tName of the remote host for this login.\n" \
+-      "\t-p\tPreserve environment."
++      "\t-h\tName of the remote host for this login\n" \
++      "\t-p\tPreserve environment"
++
++#define sum_trivial_usage \
++      "[rs] [files...]"
++#define sum_full_usage \
++      "checksum and count the blocks in a file\n\n" \
++      "Options:\n" \
++      "\t-r\tuse BSD sum algorithm (1K blocks)\n" \
++      "\t-s\tuse System V sum algorithm (512byte blocks)"
+ #define swapoff_trivial_usage \
+       "[OPTION] [DEVICE]"
+@@ -2287,32 +2493,32 @@
+ #ifdef CONFIG_FEATURE_ROTATE_LOGFILE
+-      #define USAGE_ROTATE_LOGFILE(a) a
++#  define USAGE_ROTATE_LOGFILE(a) a
+ #else
+-      #define USAGE_ROTATE_LOGFILE(a)
++#  define USAGE_ROTATE_LOGFILE(a)
+ #endif
+ #ifdef CONFIG_FEATURE_REMOTE_LOG
+-  #define USAGE_REMOTE_LOG(a) a
++#  define USAGE_REMOTE_LOG(a) a
+ #else
+-  #define USAGE_REMOTE_LOG(a)
++#  define USAGE_REMOTE_LOG(a)
+ #endif
+ #ifdef CONFIG_FEATURE_IPC_SYSLOG
+-  #define USAGE_IPC_LOG(a) a
++#  define USAGE_IPC_LOG(a) a
+ #else
+-  #define USAGE_IPC_LOG(a)
++#  define USAGE_IPC_LOG(a)
+ #endif
+ #ifdef CONFIG_SYSCTL
+ #define sysctl_trivial_usage \
+-      "[OPTIONS]... [VALUE]...\n"
++      "[OPTIONS]... [VALUE]..."
+ #define sysctl_full_usage
+       "sysctl - configure kernel parameters at runtime\n\n" \
+       "Options:\n" \
+-      "\t-n\tUse this option to disable printing of the key name when printing values.\n" \
+-      "\t-w\tUse this option when you want to change a sysctl setting.\n" \
+-      "\t-p\tLoad in sysctl settings from the file specified or /etc/sysctl.conf if none given.\n" \
+-      "\t-a\tDisplay all values currently available.\n" \
+-      "\t-A\tDisplay all values currently available in table form."
++      "\t-n\tUse this option to disable printing of the key name when printing values\n" \
++      "\t-w\tUse this option when you want to change a sysctl setting\n" \
++      "\t-p\tLoad in sysctl settings from the file specified or /etc/sysctl.conf if none given\n" \
++      "\t-a\tDisplay all values currently available\n" \
++      "\t-A\tDisplay all values currently available in table form"
+ #define sysctl_example_usage
+       "sysctl [-n] variable ...\n" \
+       "sysctl [-n] -w variable=value ...\n" \
+@@ -2345,9 +2551,9 @@
+ #ifndef CONFIG_FEATURE_FANCY_TAIL
+-  #define USAGE_UNSIMPLE_TAIL(a)
++#  define USAGE_UNSIMPLE_TAIL(a)
+ #else
+-  #define USAGE_UNSIMPLE_TAIL(a) a
++#  define USAGE_UNSIMPLE_TAIL(a) a
+ #endif
+ #define tail_trivial_usage \
+       "[OPTION]... [FILE]..."
+@@ -2370,29 +2576,29 @@
+       "nameserver 10.0.0.1\n"
+ #ifdef CONFIG_FEATURE_TAR_CREATE
+-  #define USAGE_TAR_CREATE(a) a
++#  define USAGE_TAR_CREATE(a) a
+ #else
+-  #define USAGE_TAR_CREATE(a)
++#  define USAGE_TAR_CREATE(a)
+ #endif
+ #ifdef CONFIG_FEATURE_TAR_EXCLUDE
+-  #define USAGE_TAR_EXCLUDE(a) a
++#  define USAGE_TAR_EXCLUDE(a) a
+ #else
+-  #define USAGE_TAR_EXCLUDE(a)
++#  define USAGE_TAR_EXCLUDE(a)
+ #endif
+ #ifdef CONFIG_FEATURE_TAR_GZIP
+-  #define USAGE_TAR_GZIP(a) a
++#  define USAGE_TAR_GZIP(a) a
+ #else
+-  #define USAGE_TAR_GZIP(a)
++#  define USAGE_TAR_GZIP(a)
+ #endif
+ #ifdef CONFIG_FEATURE_TAR_BZIP2
+-  #define USAGE_TAR_BZIP2(a) a
++#  define USAGE_TAR_BZIP2(a) a
+ #else
+-  #define USAGE_TAR_BZIP2(a)
++#  define USAGE_TAR_BZIP2(a)
+ #endif
+ #ifdef CONFIG_FEATURE_TAR_COMPRESS
+-  #define USAGE_TAR_COMPRESS(a) a
++#  define USAGE_TAR_COMPRESS(a) a
+ #else
+-  #define USAGE_TAR_COMPRESS(a)
++#  define USAGE_TAR_COMPRESS(a)
+ #endif
+ #define tar_trivial_usage \
+@@ -2430,7 +2636,7 @@
+       "\t-a\tappend to the given FILEs, do not overwrite\n" \
+       "\t-i\tignore interrupt signals (SIGINT)"
+ #define tee_example_usage \
+-      "$ echo "Hello" | tee /tmp/foo\n" \
++      "$ echo \"Hello\" | tee /tmp/foo\n" \
+       "$ cat /tmp/foo\n" \
+       "Hello\n"
+@@ -2441,17 +2647,17 @@
+       "Telnet is used to establish interactive communication with another\n" \
+       "computer over a network using the TELNET protocol.\n\n" \
+       "Options:\n" \
+-      "\t-a\t\tAttempt an automatic login with the USER variable.\n" \
+-      "\t-l USER\t\tAttempt an automatic login with the USER argument.\n" \
++      "\t-a\t\tAttempt an automatic login with the USER variable\n" \
++      "\t-l USER\t\tAttempt an automatic login with the USER argument\n" \
+       "\tHOST\t\tThe official name, alias or the IP address of the\n" \
+       "\t\t\tremote host.\n" \
+-      "\tPORT\t\tThe remote port number to connect to. If it is not\n" \
++      "\tPORT\t\tThe remote port number to connect to.  If it is not\n" \
+       "\t\t\tspecified, the default telnet (23) port is used."
+ #else
+ #define telnet_trivial_usage \
+       "HOST [PORT]"
+ #define telnet_full_usage \
+-      "Telnet is used to establish interactive communication with another\n"\
++      "Telnet is used to establish interactive communication with another\n" \
+       "computer over a network using the TELNET protocol."
+ #endif
+@@ -2459,19 +2665,19 @@
+ #define telnetd_trivial_usage \
+       "(inetd mode) [OPTION]"
+ #define telnetd_full_usage \
+-      "Telnetd uses incoming TELNET connections via inetd.\n"\
++      "Telnetd uses incoming TELNET connections via inetd.\n" \
+       "Options:\n" \
+       "\t-l LOGIN\texec LOGIN on connect (default /bin/sh)\n" \
+-      "\t-f issue_file\tDisplay issue_file instead of /etc/issue."
++      "\t-f issue_file\tDisplay issue_file instead of /etc/issue"
+ #else
+ #define telnetd_trivial_usage \
+       "[OPTION]"
+ #define telnetd_full_usage \
+-      "Telnetd listens for incoming TELNET connections on PORT.\n"\
++      "Telnetd listens for incoming TELNET connections on PORT.\n" \
+       "Options:\n" \
+-      "\t-p PORT\tlisten for connections on PORT (default 23)\n"\
+-      "\t-l LOGIN\texec LOGIN on connect (default /bin/sh)\n"\
+-      "\t-f issue_file\tDisplay issue_file instead of /etc/issue."
++      "\t-p PORT\tlisten for connections on PORT (default 23)\n" \
++      "\t-l LOGIN\texec LOGIN on connect (default /bin/sh)\n" \
++      "\t-f issue_file\tDisplay issue_file instead of /etc/issue"
+ #endif
+ #define test_trivial_usage \
+@@ -2494,19 +2700,19 @@
+       "1\n"
+ #ifdef CONFIG_FEATURE_TFTP_GET
+-  #define USAGE_TFTP_GET(a) a
++#  define USAGE_TFTP_GET(a) a
+ #else
+-  #define USAGE_TFTP_GET(a)
++#  define USAGE_TFTP_GET(a)
+ #endif
+ #ifdef CONFIG_FEATURE_TFTP_PUT
+-  #define USAGE_TFTP_PUT(a) a
++#  define USAGE_TFTP_PUT(a) a
+ #else
+-  #define USAGE_TFTP_PUT(a)
++#  define USAGE_TFTP_PUT(a)
+ #endif
+ #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
+-  #define USAGE_TFTP_BS(a) a
++#  define USAGE_TFTP_BS(a) a
+ #else
+-  #define USAGE_TFTP_BS(a)
++#  define USAGE_TFTP_BS(a)
+ #endif
+ #define tftp_trivial_usage \
+@@ -2514,16 +2720,16 @@
+ #define tftp_full_usage \
+       "Transfers a file from/to a tftp server using \"octet\" mode.\n\n" \
+       "Options:\n" \
+-      "\t-l FILE\tLocal FILE.\n" \
+-      "\t-r FILE\tRemote FILE." \
+-        USAGE_TFTP_GET(       \
+-        "\n\t-g\tGet file." \
+-        ) \
+-        USAGE_TFTP_PUT(       \
+-      "\n\t-p\tPut file." \
++      "\t-l FILE\tLocal FILE\n" \
++      "\t-r FILE\tRemote FILE" \
++      USAGE_TFTP_GET( \
++      "\n\t-g\tGet file" \
++      ) \
++      USAGE_TFTP_PUT( \
++      "\n\t-p\tPut file" \
+       ) \
+       USAGE_TFTP_BS( \
+-      "\n\t-b SIZE\tTransfer blocks of SIZE octets." \
++      "\n\t-b SIZE\tTransfer blocks of SIZE octets" \
+       )
+ #define time_trivial_usage \
+       "[OPTION]... COMMAND [ARGS...]"
+@@ -2531,7 +2737,7 @@
+       "Runs the program COMMAND with arguments ARGS.  When COMMAND finishes,\n" \
+       "COMMAND's resource usage information is displayed\n\n" \
+       "Options:\n" \
+-      "\t-v\tDisplays verbose resource usage information."
++      "\t-v\tDisplays verbose resource usage information"
+ #define top_trivial_usage \
+       "[-d <seconds>]"
+@@ -2565,11 +2771,11 @@
+       "\t-d\tdelete input characters coded STRING1\n" \
+       "\t-s\tsqueeze multiple output characters of STRING2 into one character"
+ #define tr_example_usage \
+-      "$ echo "gdkkn vnqkc" | tr [a-y] [b-z]\n" \
++      "$ echo \"gdkkn vnqkc\" | tr [a-y] [b-z]\n" \
+       "hello world\n"
+ #define traceroute_trivial_usage \
+-      "[-dnrv] [-m max_ttl] [-p port#] [-q nqueries]\n"\
++      "[-dnrv] [-m max_ttl] [-p port#] [-q nqueries]\n" \
+       "\t[-s src_addr] [-t tos] [-w wait] host [data size]"
+ #define traceroute_full_usage \
+       "trace the route ip packets follow going to \"host\"\n" \
+@@ -2587,7 +2793,7 @@
+       "\t-t tos\tSet the type-of-service in probe packets to the following value\n" \
+       "\t\t(default 0)\n" \
+       "\t-w wait\tSet the time (in seconds) to wait for a response to a probe\n" \
+-      "\t\t(default 3 sec.)."
++      "\t\t(default 3 sec.)"
+ #define true_trivial_usage \
+@@ -2602,7 +2808,7 @@
+ #define tty_trivial_usage \
+       ""
+ #define tty_full_usage \
+-      "Print the file name of the terminal connected to standard input.\n\n"\
++      "Print the file name of the terminal connected to standard input.\n\n" \
+       "Options:\n" \
+       "\t-s\tprint nothing, only return an exit status"
+ #define tty_example_usage \
+@@ -2616,9 +2822,9 @@
+       "\t-H,\t--hostname=HOSTNAME\tClient hostname\n" \
+       "\t-h,\t                   \tAlias for -H\n" \
+       "\t-f,\t--foreground\tDo not fork after getting lease\n" \
+-      "\t-b,\t--background\tFork to background if lease cannot be immediately negotiated.\n" \
++      "\t-b,\t--background\tFork to background if lease cannot be immediately negotiated\n" \
+       "\t-i,\t--interface=INTERFACE\tInterface to use (default: eth0)\n" \
+-      "\t-n,\t--now\tExit with failure if lease cannot be immediately negotiated.\n" \
++      "\t-n,\t--now\tExit with failure if lease cannot be immediately negotiated\n" \
+       "\t-p,\t--pidfile=file\tStore process ID of daemon in file\n" \
+       "\t-q,\t--quit\tQuit after obtaining lease\n" \
+       "\t-r,\t--request=IP\tIP address to request (default: none)\n" \
+@@ -2632,9 +2838,9 @@
+       ""
+ #ifdef CONFIG_FEATURE_MOUNT_FORCE
+-  #define USAGE_MOUNT_FORCE(a) a
++#  define USAGE_MOUNT_FORCE(a) a
+ #else
+-  #define USAGE_MOUNT_FORCE(a)
++#  define USAGE_MOUNT_FORCE(a)
+ #endif
+ #define umount_trivial_usage \
+       "[flags] FILESYSTEM|DIRECTORY"
+@@ -2769,7 +2975,7 @@
+ #define vi_full_usage \
+       "edit FILE.\n\n" \
+       "Options:\n" \
+-      "\t-R\tRead-only- do not write to the file."
++      "\t-R\tRead-only- do not write to the file"
+ #define vlock_trivial_usage \
+       "[OPTIONS]"
+@@ -2783,7 +2989,7 @@
+ #define watch_full_usage \
+       "Executes a program periodically.\n" \
+       "Options:\n" \
+-      "\t-n\tLoop period in seconds - default is 2."
++      "\t-n\tLoop period in seconds - default is 2"
+ #define watch_example_usage \
+       "$ watch date\n" \
+       "Mon Dec 17 10:31:40 GMT 2000\n" \
+@@ -2795,7 +3001,7 @@
+ #define watchdog_full_usage \
+       "Periodically write to watchdog device DEV.\n" \
+       "Options:\n" \
+-      "\t-t\tTimer period in seconds - default is 30."
++      "\t-t\tTimer period in seconds - default is 30"
+ #define wc_trivial_usage \
+       "[OPTION]... [FILE]..."
+@@ -2832,9 +3038,9 @@
+       "/bin/login\n"
+ #define who_trivial_usage \
+-        " "
++      " "
+ #define who_full_usage \
+-        "Prints the current user names and related information"
++      "Prints the current user names and related information"
+ #define whoami_trivial_usage \
+       ""
+@@ -2867,7 +3073,7 @@
+       "\t-r\tDo not run command for empty readed lines\n" \
+       USAGE_XARGS_TERMOPT("\t-x\tExit if the size is exceeded\n") \
+       USAGE_XARGS_ZERO_TERM("\t-0\tInput filenames are terminated by a null character\n") \
+-      "\t-t\tPrint the command line on stderr before executing it."
++      "\t-t\tPrint the command line on stderr before executing it"
+ #define xargs_example_usage \
+       "$ ls | xargs gzip\n" \
+       "$ find . -name '*.c' -print | xargs rm\n"
+@@ -2882,4 +3088,14 @@
+ #define zcat_full_usage \
+       "Uncompress to stdout."
++#define zcip_trivial_usage \
++      "[OPTIONS] ifname script"
++#define zcip_full_usage \
++      "zcip manages a ZeroConf IPv4 link-local address.\n" \
++      "Options:\n" \
++      "\t-f              foreground mode\n" \
++      "\t-q              quit after address (no daemon)\n" \
++      "\t-r 169.254.x.x  request this address first\n" \
++      "\t-v              verbose; show version\n"
++
+ #endif /* __BB_USAGE_H__ */
+diff -Nur busybox-1.00/init/init.c busybox/init/init.c
+--- busybox-1.00/init/init.c   2004-10-08 10:21:54.000000000 +0200
++++ busybox/init/init.c        2005-06-04 08:20:20.000000000 +0200
+@@ -453,6 +453,7 @@
+               signal(SIGINT, SIG_DFL);
+               signal(SIGTERM, SIG_DFL);
+               signal(SIGHUP, SIG_DFL);
++              signal(SIGQUIT, SIG_DFL);
+               signal(SIGCONT, SIG_DFL);
+               signal(SIGSTOP, SIG_DFL);
+               signal(SIGTSTP, SIG_DFL);
+@@ -693,6 +694,7 @@
+       /* first disable all our signals */
+       sigemptyset(&block_signals);
+       sigaddset(&block_signals, SIGHUP);
++      sigaddset(&block_signals, SIGQUIT);
+       sigaddset(&block_signals, SIGCHLD);
+       sigaddset(&block_signals, SIGUSR1);
+       sigaddset(&block_signals, SIGUSR2);
+@@ -737,6 +739,7 @@
+                       /* unblock all signals, blocked in shutdown_system() */
+                       sigemptyset(&unblock_signals);
+                       sigaddset(&unblock_signals, SIGHUP);
++                      sigaddset(&unblock_signals, SIGQUIT);
+                       sigaddset(&unblock_signals, SIGCHLD);
+                       sigaddset(&unblock_signals, SIGUSR1);
+                       sigaddset(&unblock_signals, SIGUSR2);
+@@ -1097,6 +1100,7 @@
+       /* Set up sig handlers  -- be sure to
+        * clear all of these in run() */
+       signal(SIGHUP, exec_signal);
++      signal(SIGQUIT, exec_signal);
+       signal(SIGUSR1, halt_signal);
+       signal(SIGUSR2, halt_signal);
+       signal(SIGINT, ctrlaltdel_signal);
+diff -Nur busybox-1.00/libbb/Makefile.in busybox/libbb/Makefile.in
+--- busybox-1.00/libbb/Makefile.in     2004-10-08 09:45:31.000000000 +0200
++++ busybox/libbb/Makefile.in  2005-06-04 08:20:15.000000000 +0200
+@@ -53,7 +53,7 @@
+ LIBBB_MSRC0:=$(srcdir)/messages.c
+ LIBBB_MOBJ0:=full_version.o \
+       memory_exhausted.o invalid_date.o io_error.o \
+-      write_error.o name_longer_than_foo.o unknown.o \
++      read_error.o write_error.o name_longer_than_foo.o unknown.o \
+       can_not_create_raw_socket.o perm_denied_are_you_root.o \
+       shadow_file.o passwd_file.o group_file.o gshadow_file.o nologin_file.o \
+       securetty_file.o motd_file.o \
+diff -Nur busybox-1.00/libbb/concat_path_file.c busybox/libbb/concat_path_file.c
+--- busybox-1.00/libbb/concat_path_file.c      2004-03-15 09:28:41.000000000 +0100
++++ busybox/libbb/concat_path_file.c   2005-06-04 08:20:15.000000000 +0200
+@@ -34,11 +34,11 @@
+       char *lc;
+       if (!path)
+-          path="";
++              path = "";
+       lc = last_char_is(path, '/');
+       while (*filename == '/')
+               filename++;
+-      bb_xasprintf(&outbuf, "%s%s%s", path, (lc==NULL)? "/" : "", filename);
++      bb_xasprintf(&outbuf, "%s%s%s", path, (lc==NULL ? "/" : ""), filename);
+       return outbuf;
+ }
+diff -Nur busybox-1.00/libbb/copy_file.c busybox/libbb/copy_file.c
+--- busybox-1.00/libbb/copy_file.c     2004-04-19 14:28:02.000000000 +0200
++++ busybox/libbb/copy_file.c  2005-06-04 08:20:15.000000000 +0200
+@@ -54,10 +54,11 @@
+               }
+       } else {
+               if (source_stat.st_dev == dest_stat.st_dev &&
+-                      source_stat.st_ino == dest_stat.st_ino) {
+-              bb_error_msg("`%s' and `%s' are the same file", source, dest);
+-              return -1;
+-      }
++                      source_stat.st_ino == dest_stat.st_ino)
++              {
++                      bb_error_msg("`%s' and `%s' are the same file", source, dest);
++                      return -1;
++              }
+               dest_exists = 1;
+       }
+diff -Nur busybox-1.00/libbb/copyfd.c busybox/libbb/copyfd.c
+--- busybox-1.00/libbb/copyfd.c        2004-03-15 09:28:41.000000000 +0100
++++ busybox/libbb/copyfd.c     2005-06-04 08:20:15.000000000 +0200
+@@ -2,7 +2,7 @@
+ /*
+  * Utility routines.
+  *
+- * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
++ * Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -25,6 +25,7 @@
+ #include <unistd.h>
+ #include "busybox.h"
++#include "libbb.h"
+ #if BUFSIZ < 4096
+@@ -33,46 +34,59 @@
+ #endif
+-/* If size is 0 copy until EOF */
+-static size_t bb_full_fd_action(int src_fd, int dst_fd, const size_t size)
++static size_t bb_full_fd_action(int src_fd, int dst_fd, const size_t size2)
+ {
+-      size_t read_total = 0;
+-      RESERVE_CONFIG_BUFFER(buffer,BUFSIZ);
++      int status;
++      size_t xread, wrote, total, size = size2;
+-      while ((size == 0) || (read_total < size)) {
+-              size_t read_try;
+-              ssize_t read_actual;
+-
+-              if ((size == 0) || (size - read_total > BUFSIZ)) {
+-                      read_try = BUFSIZ;
+-              } else {
+-                      read_try = size - read_total;
+-              }
++      if (src_fd < 0) {
++              return -1;
++      }
+-              read_actual = safe_read(src_fd, buffer, read_try);
+-              if (read_actual > 0) {
+-                      if ((dst_fd >= 0) && (bb_full_write(dst_fd, buffer, (size_t) read_actual) != read_actual)) {
+-                              bb_perror_msg(bb_msg_write_error);      /* match Read error below */
++      if (size == 0) {
++              /* If size is 0 copy until EOF */
++              size = ULONG_MAX;
++      }
++
++      {
++              RESERVE_CONFIG_BUFFER(buffer,BUFSIZ);
++              total = 0;
++              wrote = 0;
++              status = -1;
++              while (total < size)
++              {
++                      xread = BUFSIZ;
++                      if (size < (total + BUFSIZ))
++                              xread = size - total;
++                      xread = bb_full_read(src_fd, buffer, xread);
++                      if (xread > 0) {
++                              if (dst_fd < 0) {
++                                      /* A -1 dst_fd means we need to fake it... */
++                                      wrote = xread;
++                              } else {
++                                      wrote = bb_full_write(dst_fd, buffer, xread);
++                              }
++                              if (wrote < xread) {
++                                      bb_perror_msg(bb_msg_write_error);
++                                      break;
++                              }
++                              total += wrote;
++                      } else if (xread < 0) {
++                              bb_perror_msg(bb_msg_read_error);
++                              break;
++                      } else if (xread == 0) {
++                              /* All done. */
++                              status = 0;
+                               break;
+                       }
+               }
+-              else if (read_actual == 0) {
+-                      if (size) {
+-                              bb_error_msg("Unable to read all data");
+-                      }
+-                      break;
+-              } else {
+-                      /* read_actual < 0 */
+-                      bb_perror_msg("Read error");
+-                      break;
+-              }
+-
+-              read_total += read_actual;
++              RELEASE_CONFIG_BUFFER(buffer);
+       }
+-      RELEASE_CONFIG_BUFFER(buffer);
+-
+-      return(read_total);
++      if (status == 0 || total)
++              return total;
++      /* Some sortof error occured */
++      return -1;
+ }
+diff -Nur busybox-1.00/libbb/find_pid_by_name.c busybox/libbb/find_pid_by_name.c
+--- busybox-1.00/libbb/find_pid_by_name.c      2004-03-15 09:28:42.000000000 +0100
++++ busybox/libbb/find_pid_by_name.c   2005-06-04 08:20:15.000000000 +0200
+@@ -45,11 +45,8 @@
+       procps_status_t * p;
+       pidList = xmalloc(sizeof(long));
+-#ifdef CONFIG_SELINUX
+-      while ((p = procps_scan(0, 0, NULL)) != 0) {
+-#else
+-      while ((p = procps_scan(0)) != 0) {
+-#endif
++      while ((p = procps_scan(0)) != 0) 
++      {
+               if (strncmp(p->short_cmd, pidName, COMM_LEN-1) == 0) {
+                       pidList=xrealloc( pidList, sizeof(long) * (i+2));
+                       pidList[i++]=p->pid;
+diff -Nur busybox-1.00/libbb/get_line_from_file.c busybox/libbb/get_line_from_file.c
+--- busybox-1.00/libbb/get_line_from_file.c    2004-03-15 09:28:42.000000000 +0100
++++ busybox/libbb/get_line_from_file.c 2005-06-04 08:20:15.000000000 +0200
+@@ -44,7 +44,8 @@
+                       linebuf = xrealloc(linebuf, linebufsz += GROWBY);
+               }
+               linebuf[idx++] = (char)ch;
+-              if (ch == '\n' || ch == '\0') {
++              if (!ch) return linebuf;
++              if (c<2 && ch == '\n') {
+                       if (c) {
+                               --idx;
+                       }
+@@ -71,6 +72,11 @@
+       return private_get_line_from_file(file, 1);
+ }
++extern char *bb_get_chunk_from_file(FILE *file)
++{
++      return private_get_line_from_file(file, 2);
++}
++
+ /* END CODE */
+ /*
+diff -Nur busybox-1.00/libbb/getopt_ulflags.c busybox/libbb/getopt_ulflags.c
+--- busybox-1.00/libbb/getopt_ulflags.c        2004-02-05 14:49:29.000000000 +0100
++++ busybox/libbb/getopt_ulflags.c     2005-06-04 08:20:15.000000000 +0200
+@@ -26,146 +26,270 @@
+ #include <stdlib.h>
+ #include "libbb.h"
+-/*
+-You can set bb_opt_complementaly as string with one or more
+-complementaly or incongruously options.
+-If sequential founded option haved from this string
+-then your incongruously pairs unsets and complementaly make add sets.
+-Format:
+-one char - option for check,
+-chars - complementaly option for add sets.
+-- chars - option triggered for unsets.
+-~ chars - option incongruously.
+-*       - option list, called add_to_list(*ptr_from_usaged, optarg)
+-:       - separator.
+-Example: du applet can have options "-s" and "-d size"
+-If getopt found -s then -d option flag unset or if found -d then -s unset.
+-For this result you must set bb_opt_complementaly = "s-d:d-s".
+-Result have last option flag only from called arguments.
+-Warning! You can check returned flag, pointer to "d:" argument seted
+-to own optarg always.
+-Example two: cut applet must only one type of list may be specified,
+-and -b, -c and -f incongruously option, overwited option is error also.
+-You must set bb_opt_complementaly = "b~cf:c~bf:f~bc".
+-If called have more one specified, return value have error flag -
+-high bite set (0x80000000UL).
+-Example three: grep applet can have one or more "-e pattern" arguments.
+-You should use bb_getopt_ulflags() as
+-llist_t *paterns;
+-bb_opt_complementaly = "e*";
+-bb_getopt_ulflags (argc, argv, "e:", &paterns);
++/*                  Documentation !
++
++unsigned long
++bb_getopt_ulflags (int argc, char **argv, const char *applet_opts, ...)
++
++          The command line options must be declared in const char
++          *applet_opts as a string of chars, for example:
++
++          flags = bb_getopt_ulflags(argc, argv, "rnug");
++
++          If one of the given options is found, a flag value is added to
++          the return value (an unsigned long).
++
++          The flag value is determined by the position of the char in
++          applet_opts string.  For example, in the above case:
++
++          flags = bb_getopt_ulflags(argc, argv, "rnug");
++
++          "r" will add 1    (bit 1 : 0x01)
++          "n" will add 2    (bit 2 : 0x02)
++          "u  will add 4    (bit 3 : 0x03)
++          "g" will add 8    (bit 4 : 0x04)
++
++           and so on.  You can also look at the return value as a bit 
++           field and each option sets one of bits.
++
++   ":"     If one of the options requires an argument, then add a ":"
++           after the char in applet_opts and provide a pointer to store
++           the argument.  For example:
++
++           char *pointer_to_arg_for_a;
++           char *pointer_to_arg_for_b;
++           char *pointer_to_arg_for_c;
++           char *pointer_to_arg_for_d;
++
++           flags = bb_getopt_ulflags(argc, argv, "a:b:c:d:",
++                            &pointer_to_arg_for_a, &pointer_to_arg_for_b,
++                            &pointer_to_arg_for_c, &pointer_to_arg_for_d);
++
++           The type of the pointer (char* or llist_t *) may be controlled
++           by the "*" special character that is set in the external string
++           bb_opt_complementaly (see below for more info).
++
++static const struct option bb_default_long_options[]
++
++           This struct allows you to define long options.  The syntax for
++           declaring the array is just like that of getopt's longopts.
++
++           static const struct option applet_long_options[] = {
++                   { "verbose", 0, 0, "v" },
++                   { 0, 0, 0, 0 }
++           };
++           bb_applet_long_options = applet_long_options;
++
++           The first parameter is the long option name that you would pass
++           to the applet (without the dashes).
++
++           The second field determines whether the option has an argument.
++           You can set this to 0, 1, or 2, or you can use the long named
++           defines of no_argument, required_argument, and optional_argument.
++
++           The third argument is used only when the long option does not 
++           have a corresponding short option.  In that case, it should be 
++           an integer pointer.  Otherwise (and normally), it should just
++           bet set to NULL.
++
++           The last argument is the corresponding short option (if there
++           is one of course).
++
++           Note: a good applet will make long options configurable via the
++           config process and not a required feature.  The current standard
++           is to name the config option CONFIG_FEATURE_<applet>_LONG_OPTIONS.
++
++const char *bb_opt_complementaly
++
++   ":"     The colon (":") is used to separate groups of two or more chars
++           and/or groups of chars and special characters (stating some
++           conditions to be checked).
++
++   "abc"   If groups of two or more chars are specified, the first char
++           is the main option and the other chars are secondary options.
++           Their flags will be turned on if the main option is found even
++           if they are not specifed on the command line.  For example:
++
++           bb_opt_complementaly = "abc";
++
++           flags = bb_getopt_ulflags(argc, argv, "abcd")
++
++           If getopt() finds "-a" on the command line, then
++           bb_getopt_ulflags's return value will be as if "-a -b -c" were
++           found.
++
++Special characters:
++
++   "-"     A dash between two options causes the second of the two
++           to be unset (and ignored) if it is given on the command line.
++
++           For example:
++           The du applet has the options "-s" and "-d depth".  If
++           bb_getopt_ulflags finds -s, then -d is unset or if it finds -d
++           then -s is unset.  (Note:  busybox implements the GNU
++           "--max-depth" option as "-d".)  To obtain this behavior, you 
++           set bb_opt_complementaly = "s-d:d-s".  Only one flag value is 
++           added to bb_getopt_ulflags's return value depending on the 
++           position of the options on the command line.  If one of the 
++           two options requires an argument pointer (":" in applet_opts 
++           as in "d:") optarg is set accordingly.
++
++           char *smax_print_depth;
++
++           bb_opt_complementaly = "s-d:d-s";
++           opt = bb_getopt_ulflags(argc, argv, "sd:", &smax_print_depth);
++
++           if (opt & 2) {
++                    max_print_depth = bb_xgetularg10_bnd(smax_print_depth,
++                                0, INT_MAX);
++           }
++
++   "~"     A tilde between two options, or between an option and a group
++           of options, means that they are mutually exclusive.  Unlike
++           the "-" case above, an error will be forced if the options
++           are used together.
++
++           For example:
++           The cut applet must have only one type of list specified, so
++           -b, -c and -f are mutally exclusive and should raise an error
++           if specified together.  In this case you must set
++           bb_opt_complementaly = "b~cf:c~bf:f~bc".  If two of the
++           mutually exclusive options are found, bb_getopt_ulflags's
++           return value will have the error flag set (BB_GETOPT_ERROR) so
++           that we can check for it:
++
++           if (flags & BB_GETOPT_ERROR)
++                   bb_show_usage();
++
++   "*"     A star after a char in bb_opt_complementaly means that the
++           option can occur multiple times:
++
++           For example:
++           The grep applet can have one or more "-e pattern" arguments.
++           In this case you should use bb_getopt_ulflags() as follows:
++
++           llist_t *patterns = NULL;
++
++           (this pointer must be initializated to NULL if the list is empty
++           as required by *llist_add_to(llist_t *old_head, char *new_item).)
++
++           bb_opt_complementaly = "e*";
++
++           bb_getopt_ulflags(argc, argv, "e:", &patterns);
++           $ grep -e user -e root /etc/passwd
++           root:x:0:0:root:/root:/bin/bash
++           user:x:500:500::/home/user:/bin/bash
++
+ */
+ const char *bb_opt_complementaly;
+-typedef struct
+-{
++typedef struct {
+       unsigned char opt;
+       char list_flg;
+       unsigned long switch_on;
+       unsigned long switch_off;
+       unsigned long incongruously;
+-      void **optarg;              /* char **optarg or llist_t **optarg */
++      void **optarg;               /* char **optarg or llist_t **optarg */
+ } t_complementaly;
+ /* You can set bb_applet_long_options for parse called long options */
+ static const struct option bb_default_long_options[] = {
+-     /*   { "help", 0, NULL, '?' }, */
++/*    { "help", 0, NULL, '?' }, */
+       { 0, 0, 0, 0 }
+ };
+ const struct option *bb_applet_long_options = bb_default_long_options;
+-
+ unsigned long
+ bb_getopt_ulflags (int argc, char **argv, const char *applet_opts, ...)
+ {
+-  unsigned long flags = 0;
+-  t_complementaly complementaly[sizeof(flags) * 8 + 1];
+-  int c;
+-  const unsigned char *s;
+-  t_complementaly *on_off;
+-  va_list p;
+-
+-  va_start (p, applet_opts);
+-
+-  /* skip GNU extension */
+-  s = applet_opts;
+-  if(*s == '+' || *s == '-')
+-      s++;
+-
+-  c = 0;
+-  on_off = complementaly;
+-  for (; *s; s++) {
+-      if(c >= (sizeof(flags)*8))
+-              break;
+-      on_off->opt = *s;
+-      on_off->switch_on = (1 << c);
+-      on_off->list_flg = 0;
+-      on_off->switch_off = 0;
+-      on_off->incongruously = 0;
+-      on_off->optarg = NULL;
+-      if (s[1] == ':') {
+-        on_off->optarg = va_arg (p, void **);
+-        do
++      unsigned long flags = 0;
++      t_complementaly complementaly[sizeof(flags) * 8 + 1];
++      int c;
++      const unsigned char *s;
++      t_complementaly *on_off;
++      va_list p;
++
++      va_start (p, applet_opts);
++
++      /* skip GNU extension */
++      s = applet_opts;
++      if(*s == '+' || *s == '-')
+               s++;
+-        while (s[1] == ':');
++
++      c = 0;
++      on_off = complementaly;
++      for (; *s; s++) {
++              if(c >= (sizeof(flags)*8))
++                      break;
++              on_off->opt = *s;
++              on_off->switch_on = (1 << c);
++              on_off->list_flg = 0;
++              on_off->switch_off = 0;
++              on_off->incongruously = 0;
++              on_off->optarg = NULL;
++              if (s[1] == ':') {
++                      on_off->optarg = va_arg (p, void **);
++                      do
++                              s++;
++                      while (s[1] == ':');
++              }
++              on_off++;
++              c++;
+       }
+-      on_off++;
+-      c++;
+-  }
+-  on_off->opt = 0;
+-  c = 0;
+-  for (s = bb_opt_complementaly; s && *s; s++) {
+-    t_complementaly *pair;
+-
+-    if (*s == ':') {
+-        c = 0;
+-        continue;
+-    }
+-    if (c)
+-        continue;
+-    for (on_off = complementaly; on_off->opt; on_off++)
+-        if (on_off->opt == *s)
+-          break;
+-    pair = on_off;
+-    for(s++; *s && *s != ':'; s++) {
+-      if (*s == '-' || *s == '~') {
+-        c = *s;
+-      } else if(*s == '*') {
+-      pair->list_flg++;
+-      } else {
+-        unsigned long *pair_switch = &(pair->switch_on);
+-
+-        if(c)
+-          pair_switch = c == '-' ? &(pair->switch_off) : &(pair->incongruously);
+-        for (on_off = complementaly; on_off->opt; on_off++)
+-          if (on_off->opt == *s) {
+-                *pair_switch |= on_off->switch_on;
+-                break;
+-          }
+-      }
+-    }
+-    s--;
+-  }
+-
+-  while ((c = getopt_long (argc, argv, applet_opts,
+-                          bb_applet_long_options, NULL)) > 0) {
+-      for (on_off = complementaly; on_off->opt != c; on_off++) {
+-          if(!on_off->opt)
+-                      bb_show_usage ();
++      on_off->opt = 0;
++      c = 0;
++      for (s = bb_opt_complementaly; s && *s; s++) {
++              t_complementaly *pair;
++
++              if (*s == ':') {
++                      c = 0;
++                      continue;
++              }
++              if (c)
++                      continue;
++              for (on_off = complementaly; on_off->opt; on_off++)
++                      if (on_off->opt == *s)
++                              break;
++              pair = on_off;
++              for(s++; *s && *s != ':'; s++) {
++                      if (*s == '-' || *s == '~') {
++                              c = *s;
++                      } else if(*s == '*') {
++                              pair->list_flg++;
++                      } else {
++                              unsigned long *pair_switch = &(pair->switch_on);
++                              if(c)
++                                      pair_switch = c == '-' ? &(pair->switch_off) : &(pair->incongruously);
++                              for (on_off = complementaly; on_off->opt; on_off++)
++                                      if (on_off->opt == *s) {
++                                              *pair_switch |= on_off->switch_on;
++                                              break;
++                                      }
++                      }
++              }
++              s--;
+       }
+-      if(flags & on_off->incongruously)
+-          flags |= 0x80000000UL;
+-      flags &= ~on_off->switch_off;
+-      flags |= on_off->switch_on;
+-      if(on_off->list_flg) {
+-         *(llist_t **)(on_off->optarg) =
+-              llist_add_to(*(llist_t **)(on_off->optarg), optarg);
+-      } else if (on_off->optarg) {
+-          *(char **)(on_off->optarg) = optarg;
++
++      while ((c = getopt_long (argc, argv, applet_opts,
++                               bb_applet_long_options, NULL)) > 0) {
++              for (on_off = complementaly; on_off->opt != c; on_off++) {
++                      if(!on_off->opt)
++                              bb_show_usage ();
++              }
++              if(flags & on_off->incongruously)
++                      flags |= BB_GETOPT_ERROR;
++              flags &= ~on_off->switch_off;
++              flags |= on_off->switch_on;
++              if(on_off->list_flg) {
++                      *(llist_t **)(on_off->optarg) =
++                              llist_add_to(*(llist_t **)(on_off->optarg), optarg);
++              } else if (on_off->optarg) {
++                      *(char **)(on_off->optarg) = optarg;
++              }
+       }
+-  }
+-  return flags;
++
++      return flags;
+ }
+diff -Nur busybox-1.00/libbb/hash_fd.c busybox/libbb/hash_fd.c
+--- busybox-1.00/libbb/hash_fd.c       2004-03-15 09:28:42.000000000 +0100
++++ busybox/libbb/hash_fd.c    2005-06-04 08:20:15.000000000 +0200
+@@ -197,7 +197,7 @@
+ static uint32_t bits[4] = { 0x80000000, 0x00800000, 0x00008000, 0x00000080 };
+ # endif /* __BYTE_ORDER */
+-void sha1_end(unsigned char hval[], struct sha1_ctx_t *ctx)
++static void sha1_end(unsigned char hval[], struct sha1_ctx_t *ctx)
+ {
+       uint32_t i, cnt = (uint32_t) (ctx->count[0] & SHA1_MASK);
+diff -Nur busybox-1.00/libbb/inet_common.c busybox/libbb/inet_common.c
+--- busybox-1.00/libbb/inet_common.c   2004-03-10 08:42:38.000000000 +0100
++++ busybox/libbb/inet_common.c        2005-06-04 08:20:15.000000000 +0200
+@@ -4,7 +4,7 @@
+  *
+  * Heavily modified by Manuel Novoa III       Mar 12, 2001
+  *
+- * Version:     $Id$
++ * Version:     $Id$
+  *
+  */
+diff -Nur busybox-1.00/libbb/interface.c busybox/libbb/interface.c
+--- busybox-1.00/libbb/interface.c     2004-08-26 23:45:21.000000000 +0200
++++ busybox/libbb/interface.c  2005-06-04 08:20:15.000000000 +0200
+@@ -15,7 +15,7 @@
+  *              that either displays or sets the characteristics of
+  *              one or more of the system's networking interfaces.
+  *
+- * Version:     $Id$
++ * Version:     $Id$
+  *
+  * Author:      Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
+  *              and others.  Copyright 1993 MicroWalt Corporation
+@@ -888,6 +888,20 @@
+       return sfd;
+ }
++#ifdef CONFIG_FEATURE_CLEAN_UP
++static void sockets_close(void)
++{
++      struct aftype **aft;
++      for (aft = aftypes; *aft != NULL; aft++) {
++              struct aftype *af = *aft;
++              if( af->fd != -1 ) {
++                      close(af->fd);
++                      af->fd = -1;
++              }
++      }
++}
++#endif
++
+ /* like strcmp(), but knows about numbers */
+ static int nstrcmp(const char *a, const char *b)
+ {
+@@ -986,7 +1000,7 @@
+       return err;
+ }
+-char *get_name(char *name, char *p)
++static char *get_name(char *name, char *p)
+ {
+       /* Extract <name>[:<alias>] from nul-terminated p where p matches
+          <name>[:<alias>]: after leading whitespace.
+@@ -1223,17 +1237,13 @@
+       }
+ #endif
++#ifdef SIOCGIFMAP
+       strcpy(ifr.ifr_name, ifname);
+-      if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0)
+-              memset(&ife->map, 0, sizeof(struct ifmap));
++      if (ioctl(skfd, SIOCGIFMAP, &ifr) == 0)
++              ife->map = ifr.ifr_map;
+       else
+-              memcpy(&ife->map, &ifr.ifr_map, sizeof(struct ifmap));
+-
+-      strcpy(ifr.ifr_name, ifname);
+-      if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0)
++#endif
+               memset(&ife->map, 0, sizeof(struct ifmap));
+-      else
+-              ife->map = ifr.ifr_map;
+ #ifdef HAVE_TXQUEUELEN
+       strcpy(ifr.ifr_name, ifname);
+@@ -1374,7 +1384,7 @@
+ #if HAVE_HWETHER
+ #include <net/if_arp.h>
+-#if __GLIBC__ >=2 && __GLIBC_MINOR >= 1
++#if (__GLIBC__ >=2 && __GLIBC_MINOR >= 1) || defined(_NEWLIB_VERSION)
+ #include <net/ethernet.h>
+ #else
+ #include <linux/if_ether.h>
+@@ -2078,6 +2088,8 @@
+       /* Do we have to show the current setup? */
+       status = if_print(ifname);
+-      close(skfd);
++#ifdef CONFIG_FEATURE_CLEAN_UP
++      sockets_close();
++#endif
+       exit(status < 0);
+ }
+diff -Nur busybox-1.00/libbb/loop.c busybox/libbb/loop.c
+--- busybox-1.00/libbb/loop.c  2004-08-16 10:36:28.000000000 +0200
++++ busybox/libbb/loop.c       2005-06-04 08:20:15.000000000 +0200
+@@ -19,6 +19,10 @@
+  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+  */
++#include <features.h>
++#if defined (__GLIBC__) && !defined(__UCLIBC__)
++#include <linux/posix_types.h>
++#endif
+ #include <stdio.h>
+ #include <errno.h>
+ #include <fcntl.h>
+@@ -30,7 +34,6 @@
+ /* Grumble...  The 2.6.x kernel breaks asm/posix_types.h
+  * so we get to try and cope as best we can... */
+ #include <linux/version.h>
+-#include <asm/posix_types.h>
+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+ #define __bb_kernel_dev_t   __kernel_old_dev_t
+diff -Nur busybox-1.00/libbb/messages.c busybox/libbb/messages.c
+--- busybox-1.00/libbb/messages.c      2004-03-15 09:28:42.000000000 +0100
++++ busybox/libbb/messages.c   2005-06-04 08:20:15.000000000 +0200
+@@ -36,6 +36,9 @@
+ #ifdef L_write_error
+       const char * const bb_msg_write_error = "Write Error";
+ #endif
++#ifdef L_read_error
++      const char * const bb_msg_read_error = "Read Error";
++#endif
+ #ifdef L_name_longer_than_foo
+       const char * const bb_msg_name_longer_than_foo = "Names longer than %d chars not supported.";
+ #endif
+diff -Nur busybox-1.00/libbb/procps.c busybox/libbb/procps.c
+--- busybox-1.00/libbb/procps.c        2004-08-27 00:18:58.000000000 +0200
++++ busybox/libbb/procps.c     2005-06-04 08:20:15.000000000 +0200
+@@ -16,11 +16,7 @@
+ #include "libbb.h"
+-extern procps_status_t * procps_scan(int save_user_arg0
+-#ifdef CONFIG_SELINUX
+-      , int use_selinux , security_id_t *sid
+-#endif
+-      )
++extern procps_status_t * procps_scan(int save_user_arg0)
+ {
+       static DIR *dir;
+       struct dirent *entry;
+@@ -60,16 +56,9 @@
+               my_getpwuid(curstatus.user, sb.st_uid, sizeof(curstatus.user));
+               sprintf(status, "/proc/%d/stat", pid);
++
+               if((fp = fopen(status, "r")) == NULL)
+                       continue;
+-#ifdef CONFIG_SELINUX
+-              if(use_selinux)
+-              {
+-                      if(fstat_secure(fileno(fp), &sb, sid))
+-                              continue;
+-              }
+-              else
+-#endif
+               name = fgets(buf, sizeof(buf), fp);
+               fclose(fp);
+               if(name == NULL)
+diff -Nur busybox-1.00/libbb/run_shell.c busybox/libbb/run_shell.c
+--- busybox-1.00/libbb/run_shell.c     2004-03-15 09:28:43.000000000 +0100
++++ busybox/libbb/run_shell.c  2005-06-04 08:20:15.000000000 +0200
+@@ -37,7 +37,33 @@
+ #include <ctype.h>
+ #include "libbb.h"
+ #ifdef CONFIG_SELINUX
+-#include <proc_secure.h>
++#include <selinux/selinux.h>  /* for setexeccon  */
++#endif
++
++#ifdef CONFIG_SELINUX
++static security_context_t current_sid=NULL;
++
++void
++renew_current_security_context(void)
++{
++  if  (current_sid)  
++    freecon(current_sid);  /* Release old context  */
++
++  getcon(&current_sid);  /* update */
++
++  return;
++}
++void
++set_current_security_context(security_context_t sid)
++{
++  if  (current_sid)  
++    freecon(current_sid);  /* Release old context  */
++
++  current_sid=sid;
++
++  return;
++}
++
+ #endif
+ /* Run SHELL, or DEFAULT_SHELL if SHELL is empty.
+@@ -45,11 +71,7 @@
+    If ADDITIONAL_ARGS is nonzero, pass it to the shell as more
+    arguments.  */
+-void run_shell ( const char *shell, int loginshell, const char *command, const char **additional_args
+-#ifdef CONFIG_SELINUX
+-      , security_id_t sid
+-#endif
+-)
++void run_shell ( const char *shell, int loginshell, const char *command, const char **additional_args)
+ {
+       const char **args;
+       int argno = 1;
+@@ -78,10 +100,11 @@
+       }
+       args [argno] = 0;
+ #ifdef CONFIG_SELINUX
+-      if(sid)
+-              execve_secure(shell, (char **) args, environ, sid);
+-      else
++      if ( (current_sid) && (!setexeccon(current_sid)) ) {
++          freecon(current_sid);
++          execve(shell, (char **) args, environ);
++      } else
+ #endif
+-      execv ( shell, (char **) args );
++        execv ( shell, (char **) args );
+       bb_perror_msg_and_die ( "cannot run %s", shell );
+ }
+diff -Nur busybox-1.00/libbb/syscalls.c busybox/libbb/syscalls.c
+--- busybox-1.00/libbb/syscalls.c      2004-03-15 09:28:43.000000000 +0100
++++ busybox/libbb/syscalls.c   2005-06-04 08:20:15.000000000 +0200
+@@ -29,7 +29,7 @@
+ #include <sys/syscall.h>
+ #include "libbb.h"
+-int sysfs( int option, unsigned int fs_index, char * buf)
++int sysfs(int option, unsigned int fs_index, char * buf)
+ {
+       return(syscall(__NR_sysfs, option, fs_index, buf));
+ }
+@@ -39,60 +39,59 @@
+ #ifndef __NR_pivot_root
+ #warning This kernel does not support the pivot_root syscall
+ #warning -> The pivot_root system call is being stubbed out...
+-    /* BusyBox was compiled against a kernel that did not support
+-     *  the pivot_root system call.  To make this application work,
+-     *  you will need to recompile with a kernel supporting the
+-     *  pivot_root system call.
+-     */
+-    bb_error_msg("\n\nTo make this application work, you will need to recompile\n"
+-          "BusyBox with a kernel supporting the pivot_root system call.\n");
+-    errno=ENOSYS;
+-    return -1;
++      /* BusyBox was compiled against a kernel that did not support
++       *  the pivot_root system call.  To make this application work,
++       *  you will need to recompile with a kernel supporting the
++       *  pivot_root system call.
++       */
++      bb_error_msg("\n\nTo make this application work, you will need to recompile\n"
++                   "BusyBox with a kernel supporting the pivot_root system call.\n");
++      errno = ENOSYS;
++      return -1;
+ #else
+-    return(syscall(__NR_pivot_root, new_root, put_old));
+-#endif
++      return(syscall(__NR_pivot_root, new_root, put_old));
++#endif /* __NR_pivot_root */
+ }
+-
+-/* These syscalls are not included in ancient glibc versions */
++/* These syscalls are not included in ancient glibc versions,
++   so we have to define them ourselves, whee ! */
+ #if ((__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1))
+ int bdflush(int func, int data)
+ {
+-    return(syscall(__NR_bdflush, func, data));
++      return(syscall(__NR_bdflush, func, data));
+ }
+ #ifndef __alpha__
+ # define __NR_klogctl __NR_syslog
+ int klogctl(int type, char *b, int len)
+ {
+-    return(syscall(__NR_klogctl, type, b, len));
++      return(syscall(__NR_klogctl, type, b, len));
+ }
+-#endif
++#endif /* __alpha__ */
+ int umount2(const char * special_file, int flags)
+ {
+-#ifndef __NR_pivot_root
++#ifndef __NR_umount2
+ #warning This kernel does not support the umount2 syscall
+ #warning -> The umount2 system call is being stubbed out...
+-    /* BusyBox was compiled against a kernel that did not support
+-     *  the umount2 system call.  To make this application work,
+-     *  you will need to recompile with a kernel supporting the
+-     *  umount2 system call.
+-     */
+-    bb_error_msg("\n\nTo make this application work, you will need to recompile\n"
+-          "BusyBox with a kernel supporting the umount2 system call.\n");
+-    errno=ENOSYS;
+-    return -1;
++      /* BusyBox was compiled against a kernel that did not support
++       *  the umount2 system call.  To make this application work,
++       *  you will need to recompile with a kernel supporting the
++       *  umount2 system call.
++       */
++      bb_error_msg("\n\nTo make this application work, you will need to recompile\n"
++                   "BusyBox with a kernel supporting the umount2 system call.\n");
++      errno = ENOSYS;
++      return -1;
+ #else
+-    return(syscall(__NR_umount2, special_file, flags));
+-#endif
++      return(syscall(__NR_umount2, special_file, flags));
++#endif /* __NR_pivot_root */
+ }
+-
+-#endif
++#endif /* old glibc check */
+ /* END CODE */
+diff -Nur busybox-1.00/loginutils/delgroup.c busybox/loginutils/delgroup.c
+--- busybox-1.00/loginutils/delgroup.c 2003-07-14 23:50:51.000000000 +0200
++++ busybox/loginutils/delgroup.c      2005-06-04 08:20:18.000000000 +0200
+@@ -59,4 +59,4 @@
+       return (EXIT_SUCCESS);
+ }
+-/* $Id$ */
++/* $Id$ */
+diff -Nur busybox-1.00/loginutils/delline.c busybox/loginutils/delline.c
+--- busybox-1.00/loginutils/delline.c  2003-07-14 23:50:51.000000000 +0200
++++ busybox/loginutils/delline.c       2005-06-04 08:20:18.000000000 +0200
+@@ -110,4 +110,4 @@
+ }
+-/* $Id$ */
++/* $Id$ */
+diff -Nur busybox-1.00/loginutils/deluser.c busybox/loginutils/deluser.c
+--- busybox-1.00/loginutils/deluser.c  2003-07-14 22:20:45.000000000 +0200
++++ busybox/loginutils/deluser.c       2005-06-04 08:20:18.000000000 +0200
+@@ -65,4 +65,4 @@
+       return (EXIT_SUCCESS);
+ }
+-/* $Id$ */
++/* $Id$ */
+diff -Nur busybox-1.00/loginutils/getty.c busybox/loginutils/getty.c
+--- busybox-1.00/loginutils/getty.c    2004-08-27 00:26:26.000000000 +0200
++++ busybox/loginutils/getty.c 2005-06-04 08:20:18.000000000 +0200
+@@ -85,7 +85,7 @@
+ #define DEF_QUIT      CTL('\\')       /* default quit char */
+ #define DEF_KILL      CTL('U')        /* default kill char */
+ #define DEF_EOF               CTL('D')        /* default EOF char */
+-#define DEF_EOL               0
++#define DEF_EOL               '\n'
+ #define DEF_SWITCH    0                       /* default switch char */
+  /*
+@@ -151,7 +151,7 @@
+ /* Storage for things detected while the login name was read. */
+-struct chardata {
++static struct chardata {
+       int erase;                                      /* erase character */
+       int kill;                                       /* kill character */
+       int eol;                                        /* end-of-line character */
+@@ -161,7 +161,7 @@
+ /* Initial values for the above. */
+-struct chardata init_chardata = {
++static struct chardata init_chardata = {
+       DEF_ERASE,                                      /* default erase character */
+       DEF_KILL,                                       /* default kill character */
+       13,                                                     /* default eol char */
+diff -Nur busybox-1.00/loginutils/login.c busybox/loginutils/login.c
+--- busybox-1.00/loginutils/login.c    2004-08-27 00:26:26.000000000 +0200
++++ busybox/loginutils/login.c 2005-06-04 08:20:18.000000000 +0200
+@@ -17,10 +17,10 @@
+ #include "busybox.h"
+ #ifdef CONFIG_SELINUX
+-#include <flask_util.h>
+-#include <get_sid_list.h>
+-#include <proc_secure.h>
+-#include <fs_secure.h>
++#include <selinux/selinux.h>  /* for is_selinux_enabled()  */
++#include <selinux/get_context_list.h> /* for get_default_context() */
++#include <selinux/flask.h> /* for security class definitions  */
++#include <errno.h>
+ #endif
+ #ifdef CONFIG_FEATURE_U_W_TMP
+@@ -28,7 +28,7 @@
+ static void checkutmp(int picky);
+ static void setutmp(const char *name, const char *line);
+ /* Stuff global to this file */
+-struct utmp utent;
++static struct utmp utent;
+ #endif
+ // login defines
+@@ -79,8 +79,7 @@
+       char *opt_host = 0;
+       int alarmstarted = 0;
+ #ifdef CONFIG_SELINUX
+-      int flask_enabled = is_flask_enabled();
+-      security_id_t sid = 0, old_tty_sid, new_tty_sid;
++      security_context_t stat_sid = NULL, sid = NULL, old_tty_sid=NULL, new_tty_sid=NULL;
+ #endif
+       username[0]=0;
+@@ -225,41 +224,45 @@
+ #ifdef CONFIG_FEATURE_U_W_TMP
+       setutmp ( username, tty );
+ #endif
++
++      if ( *tty != '/' )
++              snprintf ( full_tty, sizeof( full_tty ) - 1, "/dev/%s", tty);
++      else
++              safe_strncpy ( full_tty, tty, sizeof( full_tty ) - 1 );
++
+ #ifdef CONFIG_SELINUX
+-      if (flask_enabled)
++      if (is_selinux_enabled())
+       {
+               struct stat st;
++              int rc;
+-              if (get_default_sid(username, 0, &sid))
++              if (get_default_context(username, NULL, &sid))
+               {
+                       fprintf(stderr, "Unable to get SID for %s\n", username);
+                       exit(1);
+               }
+-              if (stat_secure(tty, &st, &old_tty_sid))
++              rc = getfilecon(full_tty,&stat_sid);
++              freecon(stat_sid);
++              if ((rc<0) || (stat(full_tty, &st)<0))
+               {
+-                      fprintf(stderr, "stat_secure(%.100s) failed: %.100s\n", tty, strerror(errno));
++                      fprintf(stderr, "stat_secure(%.100s) failed: %.100s\n", full_tty, strerror(errno));
+                       return EXIT_FAILURE;
+               }
+-              if (security_change_sid (sid, old_tty_sid, SECCLASS_CHR_FILE, &new_tty_sid) != 0)
++              if (security_compute_relabel (sid, old_tty_sid, SECCLASS_CHR_FILE, &new_tty_sid) != 0)
+               {
+-                      fprintf(stderr, "security_change_sid(%.100s) failed: %.100s\n", tty, strerror(errno));
++                      fprintf(stderr, "security_change_sid(%.100s) failed: %.100s\n", full_tty, strerror(errno));
+                       return EXIT_FAILURE;
+               }
+-              if(chsid(tty, new_tty_sid) != 0)
++              if(setfilecon(full_tty, new_tty_sid) != 0)
+               {
+-                      fprintf(stderr, "chsid(%.100s, %d) failed: %.100s\n", tty, new_tty_sid, strerror(errno));
++                      fprintf(stderr, "chsid(%.100s, %s) failed: %.100s\n", full_tty, new_tty_sid, strerror(errno));
+                       return EXIT_FAILURE;
+               }
++              freecon(sid);
++              freecon(old_tty_sid);
++              freecon(new_tty_sid);
+       }
+-      else
+-              sid = 0;
+ #endif
+-
+-      if ( *tty != '/' )
+-              snprintf ( full_tty, sizeof( full_tty ) - 1, "/dev/%s", tty);
+-      else
+-              safe_strncpy ( full_tty, tty, sizeof( full_tty ) - 1 );
+-
+       if ( !is_my_tty ( full_tty ))
+               syslog ( LOG_ERR, "unable to determine TTY name, got %s\n", full_tty );
+@@ -279,11 +282,10 @@
+       if ( pw-> pw_uid == 0 )
+               syslog ( LOG_INFO, "root login %s\n", fromhost );
+-      run_shell ( tmp, 1, 0, 0
+ #ifdef CONFIG_SELINUX
+-      , sid
++      set_current_security_context(sid);
+ #endif
+-       );     /* exec the shell finally. */
++      run_shell ( tmp, 1, 0, 0);      /* exec the shell finally. */
+       return EXIT_FAILURE;
+ }
+@@ -387,7 +389,7 @@
+ }
+-static void motd ( )
++static void motd (void)
+ {
+       FILE *fp;
+       register int c;
+diff -Nur busybox-1.00/loginutils/passwd.c busybox/loginutils/passwd.c
+--- busybox-1.00/loginutils/passwd.c   2004-09-15 04:39:09.000000000 +0200
++++ busybox/loginutils/passwd.c        2005-06-04 08:20:18.000000000 +0200
+@@ -21,7 +21,7 @@
+ static void set_filesize_limit(int blocks);
+-int get_algo(char *a)
++static int get_algo(char *a)
+ {
+       int x = 1;                                      /* standard: MD5 */
+@@ -31,7 +31,7 @@
+ }
+-extern int update_passwd(const struct passwd *pw, char *crypt_pw)
++static int update_passwd(const struct passwd *pw, char *crypt_pw)
+ {
+       char filename[1024];
+       char buf[1025];
+diff -Nur busybox-1.00/loginutils/su.c busybox/loginutils/su.c
+--- busybox-1.00/loginutils/su.c       2004-03-15 09:28:46.000000000 +0100
++++ busybox/loginutils/su.c    2005-06-04 08:20:18.000000000 +0200
+@@ -147,11 +147,10 @@
+       change_identity ( pw );
+       setup_environment ( opt_shell, opt_loginshell, !opt_preserve, pw );
+-      run_shell ( opt_shell, opt_loginshell, opt_command, (const char**)opt_args
+ #ifdef CONFIG_SELINUX
+-      , 0
++       set_current_security_context(NULL);
+ #endif
+-      );
++      run_shell ( opt_shell, opt_loginshell, opt_command, (const char**)opt_args);
+       return EXIT_FAILURE;
+ }
+diff -Nur busybox-1.00/loginutils/sulogin.c busybox/loginutils/sulogin.c
+--- busybox-1.00/loginutils/sulogin.c  2004-05-01 03:27:30.000000000 +0200
++++ busybox/loginutils/sulogin.c       2005-06-04 08:20:18.000000000 +0200
+@@ -153,6 +153,12 @@
+       puts("Entering System Maintenance Mode\n");
+       fflush(stdout);
+       syslog(LOG_INFO, "System Maintenance Mode\n");
++
++#ifdef CONFIG_SELINUX
++      renew_current_security_context();
++#endif
++
+       run_shell(pwent.pw_shell, 1, 0, 0);
++
+       return (0);
+ }
+diff -Nur busybox-1.00/loginutils/vlock.c busybox/loginutils/vlock.c
+--- busybox-1.00/loginutils/vlock.c    2004-05-01 03:27:30.000000000 +0200
++++ busybox/loginutils/vlock.c 2005-06-04 08:20:18.000000000 +0200
+@@ -51,7 +51,7 @@
+ static struct spwd *spw;
+ /* getspuid - get a shadow entry by uid */
+-struct spwd *getspuid(uid_t uid)
++static struct spwd *getspuid(uid_t uid)
+ {
+       struct spwd *sp;
+       struct passwd *mypw;
+diff -Nur busybox-1.00/miscutils/Config.in busybox/miscutils/Config.in
+--- busybox-1.00/miscutils/Config.in   2004-08-27 01:12:59.000000000 +0200
++++ busybox/miscutils/Config.in        2005-06-04 08:20:16.000000000 +0200
+@@ -83,6 +83,12 @@
+       help
+         Increases logging to stderr or syslog.
++config CONFIG_EJECT
++      bool "eject"
++      default n
++      help
++        Used to eject cdroms.  (defaults to /dev/cdrom)
++
+ config CONFIG_LAST
+       bool "last"
+       default n
+diff -Nur busybox-1.00/miscutils/Makefile.in busybox/miscutils/Makefile.in
+--- busybox-1.00/miscutils/Makefile.in 2004-10-08 09:45:39.000000000 +0200
++++ busybox/miscutils/Makefile.in      2005-06-04 08:20:16.000000000 +0200
+@@ -24,19 +24,20 @@
+ srcdir=$(top_srcdir)/miscutils
+ MISCUTILS-y:=
+-MISCUTILS-$(CONFIG_ADJTIMEX)          += adjtimex.o
+-MISCUTILS-$(CONFIG_CROND)               += crond.o
+-MISCUTILS-$(CONFIG_CRONTAB)             += crontab.o
+-MISCUTILS-$(CONFIG_DC)                        += dc.o
+-MISCUTILS-$(CONFIG_DEVFSD)            += devfsd.o
+-MISCUTILS-$(CONFIG_HDPARM)            += hdparm.o
+-MISCUTILS-$(CONFIG_LAST)              += last.o
+-MISCUTILS-$(CONFIG_MAKEDEVS)          += makedevs.o
+-MISCUTILS-$(CONFIG_MT)                        += mt.o
+-MISCUTILS-$(CONFIG_RX)                        += rx.o
+-MISCUTILS-$(CONFIG_STRINGS)           += strings.o
+-MISCUTILS-$(CONFIG_TIME)              += time.o
+-MISCUTILS-$(CONFIG_WATCHDOG)          += watchdog.o
++MISCUTILS-$(CONFIG_ADJTIMEX)    += adjtimex.o
++MISCUTILS-$(CONFIG_CROND)       += crond.o
++MISCUTILS-$(CONFIG_CRONTAB)     += crontab.o
++MISCUTILS-$(CONFIG_DC)          += dc.o
++MISCUTILS-$(CONFIG_DEVFSD)      += devfsd.o
++MISCUTILS-$(CONFIG_EJECT)       += eject.o
++MISCUTILS-$(CONFIG_HDPARM)      += hdparm.o
++MISCUTILS-$(CONFIG_LAST)        += last.o
++MISCUTILS-$(CONFIG_MAKEDEVS)    += makedevs.o
++MISCUTILS-$(CONFIG_MT)          += mt.o
++MISCUTILS-$(CONFIG_RX)          += rx.o
++MISCUTILS-$(CONFIG_STRINGS)     += strings.o
++MISCUTILS-$(CONFIG_TIME)        += time.o
++MISCUTILS-$(CONFIG_WATCHDOG)    += watchdog.o
+ libraries-y+=$(MISCUTILS_DIR)$(MISCUTILS_AR)
+diff -Nur busybox-1.00/miscutils/eject.c busybox/miscutils/eject.c
+--- busybox-1.00/miscutils/eject.c     1970-01-01 01:00:00.000000000 +0100
++++ busybox/miscutils/eject.c  2005-06-04 08:20:16.000000000 +0200
+@@ -0,0 +1,63 @@
++/*
++ * eject implementation for busybox
++ *
++ * Copyright (C) 2004  Peter Willis <psyphreak@phreaker.net>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++
++/*
++ * This is a simple hack of eject based on something Erik posted in #uclibc.
++ * Most of the dirty work blatantly ripped off from cat.c =)
++ */
++
++#include <fcntl.h>
++#include <sys/ioctl.h>
++#include <unistd.h>
++#include <sys/mount.h>
++#include <mntent.h> 
++#include "busybox.h"
++
++/* various defines swiped from linux/cdrom.h */
++#define CDROMCLOSETRAY            0x5319  /* pendant of CDROMEJECT  */
++#define CDROMEJECT                0x5309  /* Ejects the cdrom media */
++#define DEFAULT_CDROM             "/dev/cdrom"
++
++extern int eject_main(int argc, char **argv)
++{
++      unsigned long flags;
++      char *device;
++      struct mntent *m;
++      
++      flags = bb_getopt_ulflags(argc, argv, "t");
++      device=argv[optind] ? : DEFAULT_CDROM;
++      
++      if((m = find_mount_point(device, bb_path_mtab_file))) {
++              if(umount(m->mnt_dir))
++                      bb_error_msg_and_die("Can't umount");
++#ifdef CONFIG_FEATURE_MTAB_SUPPORT
++              else
++                      erase_mtab(m->mnt_fsname);      
++#endif
++      }
++      if (ioctl(bb_xopen( device, 
++                         (O_RDONLY | O_NONBLOCK)), 
++                ( flags ? CDROMCLOSETRAY : CDROMEJECT)))
++      {
++              bb_perror_msg_and_die(device);
++      }
++      return(EXIT_SUCCESS);
++}
+diff -Nur busybox-1.00/miscutils/hdparm.c busybox/miscutils/hdparm.c
+--- busybox-1.00/miscutils/hdparm.c    2004-07-21 00:53:59.000000000 +0200
++++ busybox/miscutils/hdparm.c 2005-06-04 08:20:16.000000000 +0200
+@@ -467,8 +467,8 @@
+ /* Busybox messages and functions */
+-const char * const bb_msg_shared_mem  ="could not %s sharedmem buf";
+-const char * const bb_msg_op_not_supp =" operation not supported on %s disks";
++static const char * const bb_msg_shared_mem   ="could not %s sharedmem buf";
++static const char * const bb_msg_op_not_supp  =" operation not supported on %s disks";
+ static void bb_ioctl(int fd, int request, void *argp, const char *string)
+ {
+diff -Nur busybox-1.00/miscutils/rx.c busybox/miscutils/rx.c
+--- busybox-1.00/miscutils/rx.c        2004-03-15 09:28:46.000000000 +0100
++++ busybox/miscutils/rx.c     2005-06-04 08:20:16.000000000 +0200
+@@ -1,6 +1,6 @@
+ /*-------------------------------------------------------------------------
+  * Filename:      xmodem.c
+- * Version:       $Id$
++ * Version:       $Id$
+  * Copyright:     Copyright (C) 2001, Hewlett-Packard Company
+  * Author:        Christopher Hoover <ch@hpl.hp.com>
+  * Description:   xmodem functionality for uploading of kernels
+diff -Nur busybox-1.00/modutils/Config.in busybox/modutils/Config.in
+--- busybox-1.00/modutils/Config.in    2004-07-20 08:09:14.000000000 +0200
++++ busybox/modutils/Config.in 2005-06-04 08:20:10.000000000 +0200
+@@ -21,7 +21,7 @@
+ config CONFIG_FEATURE_2_6_MODULES
+       bool "  Support version 2.6.x Linux kernels"
+       default n
+-      depends on CONFIG_INSMOD
++      depends on CONFIG_INSMOD 
+       help
+         Support module loading for newer 2.6.x Linux kernels.
+@@ -80,6 +80,14 @@
+       help
+         lsmod is used to display a list of loaded modules.
++config CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT
++      bool "  lsmod pretty output for 2.6.x Linux kernels "
++      default n
++      depends on CONFIG_LSMOD 
++      help
++        This option makes output format of lsmod adjusted to 
++        the format of module-init-tools for Linux kernel 2.6.
++
+ config CONFIG_FEATURE_QUERY_MODULE_INTERFACE
+       bool
+       default y
+diff -Nur busybox-1.00/modutils/insmod.c busybox/modutils/insmod.c
+--- busybox-1.00/modutils/insmod.c     2004-09-03 01:03:25.000000000 +0200
++++ busybox/modutils/insmod.c  2005-06-04 08:20:10.000000000 +0200
+@@ -109,6 +109,14 @@
+ #endif
++/* Alpha */
++#if defined(__alpha__)   
++#define MATCH_MACHINE(x) (x == EM_ALPHA)
++#define SHT_RELM       SHT_RELA
++#define Elf64_RelM     Elf64_Rela
++#define ELFCLASSM      ELFCLASS64
++#endif
++
+ /* ARM support */
+ #if defined(__arm__)
+ #define MATCH_MACHINE(x) (x == EM_ARM)
+@@ -135,6 +143,19 @@
+ #endif
+ #endif
++/* PA-RISC / HP-PA */
++#if defined(__hppa__)
++#define MATCH_MACHINE(x) (x == EM_PARISC)
++#define SHT_RELM       SHT_RELA
++#if defined(__LP64__)
++#define Elf64_RelM     Elf64_Rela
++#define ELFCLASSM      ELFCLASS64
++#else
++#define Elf32_RelM     Elf32_Rela
++#define ELFCLASSM      ELFCLASS32
++#endif
++#endif
++
+ /* H8/300 */
+ #if defined(__H8300H__) || defined(__H8300S__)
+ #define MATCH_MACHINE(x) (x == EM_H8_300)
+@@ -269,8 +290,8 @@
+ /* X86_64  */
+ #if defined(__x86_64__)
+ #define MATCH_MACHINE(x) (x == EM_X86_64)
+-#define SHT_RELM      SHT_REL
+-#define Elf64_RelM    Elf64_Rel
++#define SHT_RELM      SHT_RELA
++#define Elf64_RelM    Elf64_Rela
+ #define ELFCLASSM     ELFCLASS64
+ #endif
+@@ -308,7 +329,7 @@
+ #ifndef MODUTILS_MODULE_H
+ static const int MODUTILS_MODULE_H = 1;
+-#ident "$Id$"
++#ident "$Id$"
+ /*======================================================================*/
+ /* For sizeof() which are related to the module platform and not to the
+@@ -466,7 +487,7 @@
+ #ifndef MODUTILS_OBJ_H
+ static const int MODUTILS_OBJ_H = 1;
+-#ident "$Id$"
++#ident "$Id$"
+ /* The relocatable object is manipulated using elfin types.  */
+@@ -3432,8 +3453,8 @@
+               ".text",
+               ".rodata",
+               ".data",
+-              ".bss"
+-                      ".sbss"
++              ".bss",
++              ".sbss"
+       };
+       if (realpath(filename, real)) {
+diff -Nur busybox-1.00/modutils/lsmod.c busybox/modutils/lsmod.c
+--- busybox-1.00/modutils/lsmod.c      2004-03-15 09:28:47.000000000 +0100
++++ busybox/modutils/lsmod.c   2005-06-04 08:20:10.000000000 +0200
+@@ -164,10 +164,52 @@
+ {
+       printf("Module                  Size  Used by");
+       check_tainted();
++#if defined(CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT)
++      {
++        FILE *file;
++        char line[4096];
++        file = fopen("/proc/modules", "r");
++
++        if (!file) 
++          bb_error_msg_and_die("Opening /proc/modules");
++
++        while (fgets(line, sizeof(line), file)) {
++          char *tok;
++          
++          tok = strtok(line, " \t");
++          printf("%-19s", tok);
++          tok = strtok(NULL, " \t\n");
++          printf(" %8s", tok);
++          tok = strtok(NULL, " \t\n");
++          /* Null if no module unloading support. */
++          if (tok) {
++            printf("  %s", tok);
++            tok = strtok(NULL, "\n");
++            if (!tok)
++              tok = "";
++            /* New-style has commas, or -.  If so,
++               truncate (other fields might follow). */
++            else if (strchr(tok, ',')) {
++              tok = strtok(tok, "\t ");
++              /* Strip trailing comma. */
++              if (tok[strlen(tok)-1] == ',')
++                tok[strlen(tok)-1] = '\0';
++            } else if (tok[0] == '-'
++                       && (tok[1] == '\0' || isspace(tok[1])))
++              tok = "";
++            printf(" %s", tok);
++          }
++          printf("\n");
++        }
++        fclose(file);
++      }
++      return 0;  /* Success  */
++#else
+       if (bb_xprint_file_by_name("/proc/modules") < 0) {
+               return 0;
+       }
++#endif  /*  CONFIG_FEATURE_2_6_MODULES  */
+       return 1;
+ }
+diff -Nur busybox-1.00/modutils/modprobe.c busybox/modutils/modprobe.c
+--- busybox-1.00/modutils/modprobe.c   2004-09-24 11:18:55.000000000 +0200
++++ busybox/modutils/modprobe.c        2005-06-04 08:20:10.000000000 +0200
+@@ -61,7 +61,7 @@
+ static int autoclean, show_only, quiet, do_syslog, verbose;
+ static int k_version;
+-int parse_tag_value ( char *buffer, char **ptag, char **pvalue )
++static int parse_tag_value ( char *buffer, char **ptag, char **pvalue )
+ {
+       char *tag, *value;
+diff -Nur busybox-1.00/networking/Config.in busybox/networking/Config.in
+--- busybox-1.00/networking/Config.in  2004-09-23 22:08:46.000000000 +0200
++++ busybox/networking/Config.in       2005-06-04 08:20:05.000000000 +0200
+@@ -18,6 +18,19 @@
+       help
+         Ping hosts by ARP packets
++config CONFIG_ETHER_WAKE
++      bool "ether-wake"
++      default n
++      help
++        Send a magic packet to wake up sleeping machines.
++
++config CONFIG_FAKEIDENTD
++      bool "fakeidentd"
++      default n
++      help
++        fakeidentd listens to the ident port and returns a set fake 
++        value whatever it gets.
++
+ config CONFIG_FTPGET
+       bool "ftpget"
+       default n
+@@ -415,6 +428,14 @@
+         A simple Unix utility which reads and writes data across network
+         connections.
++config CONFIG_NC_GAPING_SECURITY_HOLE
++      bool "gaping security hole"
++      default n
++      depends on CONFIG_NC
++      help
++        Add support for executing a program after making or receiving a
++        successful connection (-e option).
++
+ config CONFIG_NETSTAT
+       bool "netstat"
+       default n
+@@ -630,5 +651,16 @@
+ source networking/udhcp/Config.in
++config CONFIG_ZCIP
++      bool "zcip"
++      default n
++      help
++        ZCIP provides ZeroConf IPv4 address selection, according to RFC 3927.
++        It's a daemon that allocates and defends a dynamically assigned
++        address on the 169.254/16 network, requiring no system administrator.
++
++        See http://www.zeroconf.org for further details, and "zcip.script"
++        in the busybox examples.
++
+ endmenu
+diff -Nur busybox-1.00/networking/Makefile.in busybox/networking/Makefile.in
+--- busybox-1.00/networking/Makefile.in        2004-10-08 09:45:43.000000000 +0200
++++ busybox/networking/Makefile.in     2005-06-04 08:20:05.000000000 +0200
+@@ -23,33 +23,36 @@
+ endif
+ srcdir=$(top_srcdir)/networking
+ NETWORKING-y:=
+-NETWORKING-$(CONFIG_ARPING)   += arping.o
+-NETWORKING-$(CONFIG_FTPGET)   += ftpgetput.o
+-NETWORKING-$(CONFIG_FTPPUT)   += ftpgetput.o
+-NETWORKING-$(CONFIG_HOSTNAME) += hostname.o
+-NETWORKING-$(CONFIG_HTTPD)    += httpd.o
+-NETWORKING-$(CONFIG_IFCONFIG) += ifconfig.o
+-NETWORKING-$(CONFIG_IFUPDOWN) += ifupdown.o
+-NETWORKING-$(CONFIG_INETD)      += inetd.o
+-NETWORKING-$(CONFIG_IP)               += ip.o
+-NETWORKING-$(CONFIG_IPCALC)   += ipcalc.o
+-NETWORKING-$(CONFIG_IPADDR)   += ipaddr.o
+-NETWORKING-$(CONFIG_IPLINK)   += iplink.o
+-NETWORKING-$(CONFIG_IPROUTE)  += iproute.o
+-NETWORKING-$(CONFIG_IPTUNNEL) += iptunnel.o
+-NETWORKING-$(CONFIG_NAMEIF)   += nameif.o
+-NETWORKING-$(CONFIG_NC)               += nc.o
+-NETWORKING-$(CONFIG_NETSTAT)  += netstat.o
+-NETWORKING-$(CONFIG_NSLOOKUP) += nslookup.o
+-NETWORKING-$(CONFIG_PING)     += ping.o
+-NETWORKING-$(CONFIG_PING6)    += ping6.o
+-NETWORKING-$(CONFIG_ROUTE)    += route.o
+-NETWORKING-$(CONFIG_TELNET)   += telnet.o
+-NETWORKING-$(CONFIG_TELNETD)  += telnetd.o
+-NETWORKING-$(CONFIG_TFTP)     += tftp.o
+-NETWORKING-$(CONFIG_TRACEROUTE)       += traceroute.o
+-NETWORKING-$(CONFIG_VCONFIG)  += vconfig.o
+-NETWORKING-$(CONFIG_WGET)     += wget.o
++NETWORKING-$(CONFIG_ARPING)       += arping.o
++NETWORKING-$(CONFIG_ETHER_WAKE)   += ether-wake.o
++NETWORKING-$(CONFIG_FAKEIDENTD)   += fakeidentd.o
++NETWORKING-$(CONFIG_FTPGET)       += ftpgetput.o
++NETWORKING-$(CONFIG_FTPPUT)       += ftpgetput.o
++NETWORKING-$(CONFIG_HOSTNAME)     += hostname.o
++NETWORKING-$(CONFIG_HTTPD)        += httpd.o
++NETWORKING-$(CONFIG_IFCONFIG)     += ifconfig.o
++NETWORKING-$(CONFIG_IFUPDOWN)     += ifupdown.o
++NETWORKING-$(CONFIG_INETD)        += inetd.o
++NETWORKING-$(CONFIG_IP)           += ip.o
++NETWORKING-$(CONFIG_IPCALC)       += ipcalc.o
++NETWORKING-$(CONFIG_IPADDR)       += ipaddr.o
++NETWORKING-$(CONFIG_IPLINK)       += iplink.o
++NETWORKING-$(CONFIG_IPROUTE)      += iproute.o
++NETWORKING-$(CONFIG_IPTUNNEL)     += iptunnel.o
++NETWORKING-$(CONFIG_NAMEIF)       += nameif.o
++NETWORKING-$(CONFIG_NC)           += nc.o
++NETWORKING-$(CONFIG_NETSTAT)      += netstat.o
++NETWORKING-$(CONFIG_NSLOOKUP)     += nslookup.o
++NETWORKING-$(CONFIG_PING)         += ping.o
++NETWORKING-$(CONFIG_PING6)        += ping6.o
++NETWORKING-$(CONFIG_ROUTE)        += route.o
++NETWORKING-$(CONFIG_TELNET)       += telnet.o
++NETWORKING-$(CONFIG_TELNETD)      += telnetd.o
++NETWORKING-$(CONFIG_TFTP)         += tftp.o
++NETWORKING-$(CONFIG_TRACEROUTE)   += traceroute.o
++NETWORKING-$(CONFIG_VCONFIG)      += vconfig.o
++NETWORKING-$(CONFIG_WGET)         += wget.o
++NETWORKING-$(CONFIG_ZCIP)         += zcip.o
+ libraries-y+=$(NETWORKING_DIR)$(NETWORKING_AR)
+@@ -57,7 +60,7 @@
+ needcrypt-$(CONFIG_FEATURE_HTTPD_AUTH_MD5) := y
+ ifeq ($(needcrypt-y),y)
+-  LIBRARIES += -lcrypt
++      LIBRARIES += -lcrypt
+ endif
+ $(NETWORKING_DIR)$(NETWORKING_AR): $(patsubst %,$(NETWORKING_DIR)%, $(NETWORKING-y))
+@@ -65,4 +68,3 @@
+ $(NETWORKING_DIR)%.o: $(srcdir)/%.c
+       $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
+-
+diff -Nur busybox-1.00/networking/arping.c busybox/networking/arping.c
+--- busybox-1.00/networking/arping.c   2003-09-26 02:33:18.000000000 +0200
++++ busybox/networking/arping.c        2005-06-04 08:20:05.000000000 +0200
+@@ -106,7 +106,7 @@
+       return err;
+ }
+-void finish(void)
++static void finish(void)
+ {
+       if (!quiet) {
+               printf("Sent %d probes (%d broadcast(s))\n", sent, brd_sent);
+@@ -129,7 +129,7 @@
+       exit(!received);
+ }
+-void catcher(void)
++static void catcher(void)
+ {
+       struct timeval tv;
+       static struct timeval start;
+@@ -151,7 +151,7 @@
+       alarm(1);
+ }
+-int recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
++static int recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
+ {
+       struct timeval tv;
+       struct arphdr *ah = (struct arphdr *) buf;
+diff -Nur busybox-1.00/networking/ether-wake.c busybox/networking/ether-wake.c
+--- busybox-1.00/networking/ether-wake.c       1970-01-01 01:00:00.000000000 +0100
++++ busybox/networking/ether-wake.c    2005-06-04 08:20:05.000000000 +0200
+@@ -0,0 +1,300 @@
++/*
++ * ether-wake.c - Send a magic packet to wake up sleeping machines.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ *
++ * Author:      Donald Becker, http://www.scyld.com/"; http://www.scyld.com/wakeonlan.html
++ * Busybox port: Christian Volkmann <haveaniceday@online.de>
++ *               Used version of ether-wake.c: v1.09 11/12/2003 Donald Becker, http://www.scyld.com/";
++ */
++
++/* full usage according Donald Becker
++ * usage: ether-wake [-i <ifname>] [-p aa:bb:cc:dd[:ee:ff]] 00:11:22:33:44:55\n"
++ *
++ *    This program generates and transmits a Wake-On-LAN (WOL)\n"
++ *    \"Magic Packet\", used for restarting machines that have been\n"
++ *    soft-powered-down (ACPI D3-warm state).\n"
++ *    It currently generates the standard AMD Magic Packet format, with\n"
++ *    an optional password appended.\n"
++ *
++ *    The single required parameter is the Ethernet MAC (station) address\n"
++ *    of the machine to wake or a host ID with known NSS 'ethers' entry.\n"
++ *    The MAC address may be found with the 'arp' program while the target\n"
++ *    machine is awake.\n"
++ *
++ *    Options:\n"
++ *            -b      Send wake-up packet to the broadcast address.\n"
++ *            -D      Increase the debug level.\n"
++ *            -i ifname       Use interface IFNAME instead of the default 'eth0'.\n"
++ *            -p <pw>         Append the four or six byte password PW to the packet.\n"
++ *                                    A password is only required for a few adapter types.\n"
++ *                                    The password may be specified in ethernet hex format\n"
++ *                                    or dotted decimal (Internet address)\n"
++ *            -p 00:22:44:66:88:aa\n"
++ *            -p 192.168.1.1\n";
++ * 
++ *
++ *    This program generates and transmits a Wake-On-LAN (WOL) "Magic Packet",
++ *    used for restarting machines that have been soft-powered-down
++ *    (ACPI D3-warm state).  It currently generates the standard AMD Magic Packet
++ *    format, with an optional password appended.
++ * 
++ *    This software may be used and distributed according to the terms
++ *    of the GNU Public License, incorporated herein by reference.
++ *    Contact the author for use under other terms.
++ * 
++ *    This source file was originally part of the network tricks package, and
++ *    is now distributed to support the Scyld Beowulf system.
++ *    Copyright 1999-2003 Donald Becker and Scyld Computing Corporation.
++ * 
++ *    The author may be reached as becker@scyld, or C/O
++ *     Scyld Computing Corporation
++ *     914 Bay Ridge Road, Suite 220
++ *     Annapolis MD 21403
++ * 
++ *   Notes:
++ *   On some systems dropping root capability allows the process to be
++ *   dumped, traced or debugged.
++ *   If someone traces this program, they get control of a raw socket.
++ *   Linux handles this safely, but beware when porting this program.
++ * 
++ *   An alternative to needing 'root' is using a UDP broadcast socket, however
++ *   doing so only works with adapters configured for unicast+broadcast Rx
++ *   filter.  That configuration consumes more power.
++*/
++
++
++#include <unistd.h>
++#include <stdlib.h>
++#include <stdio.h>
++#include <errno.h>
++#include <ctype.h>
++#include <string.h>
++
++#include <sys/socket.h>
++#include <sys/types.h>
++#include <sys/ioctl.h>
++#include <features.h>
++#include <netpacket/packet.h>
++#include <net/ethernet.h>
++#include <netdb.h>
++#include <netinet/ether.h>
++
++#ifdef __linux__
++#include <linux/if.h>
++#endif
++
++#include "busybox.h"
++
++/* Note: PF_INET, SOCK_DGRAM, IPPROTO_UDP would allow SIOCGIFHWADDR to
++ * work as non-root, but we need SOCK_PACKET to specify the Ethernet
++ * destination address.
++ */
++#ifdef PF_PACKET
++# define whereto_t sockaddr_ll
++# define make_socket() socket(PF_PACKET, SOCK_RAW, 0)
++#else
++# define whereto_t sockaddr
++# define make_socket() socket(AF_INET, SOCK_PACKET, SOCK_PACKET)
++#endif
++
++#ifdef DEBUG
++# define bb_debug_msg(fmt, args...) fprintf(stderr, fmt, ## args)
++void bb_debug_dump_packet(unsigned char *outpack, int pktsize)
++{
++      int i;
++      printf("packet dump:\n");
++      for (i = 0; i < pktsize; ++i) {
++              printf("%2.2x ", outpack[i]);
++              if (i % 20 == 19) printf("\n");
++      }
++      printf("\n\n");
++}
++#else
++# define bb_debug_msg(fmt, args...)
++# define bb_debug_dump_packet(outpack, pktsize)
++#endif
++
++static inline void get_dest_addr(const char *arg, struct ether_addr *eaddr);
++static inline int get_fill(unsigned char *pkt, struct ether_addr *eaddr, int broadcast);
++static inline int get_wol_pw(const char *ethoptarg, unsigned char *wol_passwd);
++
++int etherwake_main(int argc, char *argv[])
++{
++      char *ifname = "eth0", *pass = NULL;
++      unsigned long flags;
++      unsigned char wol_passwd[6];
++      int wol_passwd_sz = 0;
++
++      int s;                                          /* Raw socket */
++      int pktsize;
++      unsigned char outpack[1000];
++
++      struct ether_addr eaddr;
++      struct whereto_t whereto;       /* who to wake up */
++
++      /* handle misc user options */
++      flags = bb_getopt_ulflags(argc, argv, "bi:p:", &ifname, &pass);
++      if (optind == argc)
++              bb_show_usage();
++      if (pass)
++              wol_passwd_sz = get_wol_pw(pass, wol_passwd);
++
++      /* create the raw socket */
++      s = make_socket();
++      if (s < 0)
++              bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket);
++
++      /* now that we have a raw socket we can drop root */
++      setuid(getuid());
++
++      /* look up the dest mac address */
++      get_dest_addr(argv[optind], &eaddr);
++
++      /* fill out the header of the packet */
++      pktsize = get_fill(outpack, &eaddr, flags /*& 1 [OPT_BROADCAST]*/);
++
++      bb_debug_dump_packet(outpack, pktsize);
++
++      /* Fill in the source address, if possible. */
++#ifdef __linux__
++      {
++              struct ifreq if_hwaddr;
++
++              strcpy(if_hwaddr.ifr_name, ifname);
++              if (ioctl(s, SIOCGIFHWADDR, &if_hwaddr) < 0)
++                      bb_perror_msg_and_die("SIOCGIFHWADDR on %s failed", ifname);
++
++              memcpy(outpack+6, if_hwaddr.ifr_hwaddr.sa_data, 6);
++
++# ifdef DEBUG
++              {
++                      unsigned char *hwaddr = if_hwaddr.ifr_hwaddr.sa_data;
++                      printf("The hardware address (SIOCGIFHWADDR) of %s is type %d  "
++                                 "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n\n", ifname,
++                                 if_hwaddr.ifr_hwaddr.sa_family, hwaddr[0], hwaddr[1],
++                                 hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]);
++              }
++# endif
++      }
++#endif /* __linux__ */
++
++      bb_debug_dump_packet(outpack, pktsize);
++
++      /* append the password if specified */
++      if (wol_passwd_sz > 0) {
++              memcpy(outpack+pktsize, wol_passwd, wol_passwd_sz);
++              pktsize += wol_passwd_sz;
++      }
++
++      bb_debug_dump_packet(outpack, pktsize);
++
++      /* This is necessary for broadcasts to work */
++      if (flags /*& 1 [OPT_BROADCAST]*/) {
++              int one = 1;
++              if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, (void *)&one, sizeof(one)) < 0)
++                      bb_perror_msg("SO_BROADCAST");
++      }
++
++#if defined(PF_PACKET)
++      {
++              struct ifreq ifr;
++              strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
++              if (ioctl(s, SIOCGIFINDEX, &ifr) == -1)
++                      bb_perror_msg_and_die("SIOCGIFINDEX");
++              memset(&whereto, 0, sizeof(whereto));
++              whereto.sll_family = AF_PACKET;
++              whereto.sll_ifindex = ifr.ifr_ifindex;
++              /* The manual page incorrectly claims the address must be filled.
++                 We do so because the code may change to match the docs. */
++              whereto.sll_halen = ETH_ALEN;
++              memcpy(whereto.sll_addr, outpack, ETH_ALEN);
++      }
++#else
++      whereto.sa_family = 0;
++      strcpy(whereto.sa_data, ifname);
++#endif
++
++      if (sendto(s, outpack, pktsize, 0, (struct sockaddr *)&whereto, sizeof(whereto)) < 0)
++              bb_perror_msg(bb_msg_write_error);
++
++      close(s);
++
++      return EXIT_SUCCESS;
++}
++
++/* Convert the host ID string to a MAC address.
++ * The string may be a:
++ *    Host name
++ *    IP address string
++ *    MAC address string
++*/
++static inline void get_dest_addr(const char *hostid, struct ether_addr *eaddr)
++{
++      struct ether_addr *eap;
++
++      eap = ether_aton(hostid);
++      if (eap) {
++              *eaddr = *eap;
++              bb_debug_msg("The target station address is %s\n\n", ether_ntoa(eaddr));
++      } else if (ether_hostton(hostid, eaddr) == 0) {
++              bb_debug_msg("Station address for hostname %s is %s\n\n", hostid, ether_ntoa(eaddr));
++      } else
++              bb_show_usage();
++}
++
++static inline int get_fill(unsigned char *pkt, struct ether_addr *eaddr, int broadcast)
++{
++      int offset, i;
++      unsigned char *station_addr = eaddr->ether_addr_octet;
++
++      if (broadcast)
++              memset(pkt+0, 0xff, 6);
++      else
++              memcpy(pkt, station_addr, 6);
++      memcpy(pkt+6, station_addr, 6);
++      pkt[12] = 0x08;                         /* Or 0x0806 for ARP, 0x8035 for RARP */
++      pkt[13] = 0x42;
++      offset = 14;
++
++      memset(pkt+offset, 0xff, 6);
++      offset += 6;
++
++      for (i = 0; i < 16; ++i) {
++              memcpy(pkt+offset, station_addr, 6);
++              offset += 6;
++      }
++
++      return offset;
++}
++
++static inline int get_wol_pw(const char *ethoptarg, unsigned char *wol_passwd)
++{
++      int passwd[6];
++      int byte_cnt, i;
++
++      /* handle MAC format */
++      byte_cnt = sscanf(ethoptarg, "%2x:%2x:%2x:%2x:%2x:%2x",
++                        &passwd[0], &passwd[1], &passwd[2],
++                        &passwd[3], &passwd[4], &passwd[5]);
++      /* handle IP format */
++      if (byte_cnt < 4)
++              byte_cnt = sscanf(ethoptarg, "%d.%d.%d.%d",
++                                &passwd[0], &passwd[1], &passwd[2], &passwd[3]);
++      if (byte_cnt < 4) {
++              bb_error_msg("Unable to read the Wake-On-LAN pass");
++              return 0;
++      }
++
++      for (i = 0; i < byte_cnt; ++i)
++              wol_passwd[i] = passwd[i];
++
++      bb_debug_msg("password: %2.2x %2.2x %2.2x %2.2x (%d)\n\n",
++                   wol_passwd[0], wol_passwd[1], wol_passwd[2], wol_passwd[3],
++                   byte_cnt);
++
++      return byte_cnt;
++}
+diff -Nur busybox-1.00/networking/fakeidentd.c busybox/networking/fakeidentd.c
+--- busybox-1.00/networking/fakeidentd.c       1970-01-01 01:00:00.000000000 +0100
++++ busybox/networking/fakeidentd.c    2005-06-04 08:20:05.000000000 +0200
+@@ -0,0 +1,432 @@
++/* vi: set sw=4 ts=4: */
++/*
++ * A fake identd server
++ *
++ * Adapted to busybox by Thomas Lundquist <thomasez@zelow.no>
++ * Original Author: Tomi Ollila <too@iki.fi>
++ *                  http://www.guru-group.fi/~too/sw/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++
++#include <unistd.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <stdarg.h>
++#include <string.h>
++#include <fcntl.h>
++#include <signal.h>
++#include <sys/syslog.h>
++
++#include <pwd.h>
++#include <netdb.h>
++
++#include <sys/syslog.h>
++#include <sys/types.h>
++#include <sys/time.h>
++#include <time.h>
++#include <sys/socket.h>
++#include <netinet/in.h>
++#include <errno.h>
++#include <arpa/inet.h>
++#include <sys/uio.h>
++
++#include "busybox.h"
++
++#define IDENT_PORT  113
++#define MAXCONNS    20
++#define MAXIDLETIME 45
++
++static const char ident_substr[] = " : USERID : UNIX : ";
++static const int ident_substr_len = sizeof(ident_substr) - 1;
++#define PIDFILE "/var/run/identd.pid"
++
++/*
++ * We have to track the 'first connection socket' so that we 
++ * don't go around closing file descriptors for non-clients.
++ *
++ * descriptor setup normally
++ *  0 = server socket
++ *  1 = syslog fd (hopefully -- otherwise this won't work)
++ *  2 = connection socket after detached from tty. standard error before that
++ *  3 - 2 + MAXCONNS = rest connection sockets
++ *
++ * To try to make sure that syslog fd is what is "requested", the that fd
++ * is closed before openlog() call.  It can only severely fail if fd 0
++ * is initially closed.
++ */
++#define FCS 2
++
++/*
++ * FD of the connection is always the index of the connection structure
++ * in `conns' array + FCS
++ */
++static struct {
++      char buf[20];
++      int len;
++      time_t lasttime;
++} conns[MAXCONNS];
++
++/* When using global variables, bind those at least to a structure. */
++static struct {
++      const char *identuser;
++      fd_set readfds;
++      int conncnt;
++} G;
++
++/*
++ * Prototypes
++ */
++static void reply(int s, char *buf);
++static void replyError(int s, char *buf);
++
++static const char *nobodystr = "nobody"; /* this needs to be declared like this */
++static char *bind_ip_address = "0.0.0.0";
++
++static inline void movefd(int from, int to)
++{
++      if (from != to) {
++              dup2(from, to);
++              close(from);
++      }
++}
++
++static void inetbind(void)
++{
++      int s, port;
++      struct sockaddr_in addr;
++      int len = sizeof(addr);
++      int one = 1;
++      struct servent *se;
++
++      if ((se = getservbyname("identd", "tcp")) == NULL)
++              port = IDENT_PORT;
++      else
++              port = se->s_port;
++
++      if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
++              bb_perror_msg_and_die("Cannot create server socket");
++
++      setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
++
++      memset(&addr, 0, sizeof(addr));
++      addr.sin_addr.s_addr = inet_addr(bind_ip_address);
++      addr.sin_family = AF_INET;
++      addr.sin_port = htons(port);
++
++      if (bind(s, (struct sockaddr *)&addr, len) < 0)
++              bb_perror_msg_and_die("Cannot bind() port %i", IDENT_PORT);
++
++      if (listen(s, 5) < 0)
++              bb_perror_msg_and_die("Cannot listen() on port %i", IDENT_PORT);
++
++      movefd(s, 0);
++}
++
++static void delpidfile(void)
++{
++      /*
++       * Usually nobody has no write/delete access to directory /var/run/
++       * therefore if file cannot be deleted, it is truncated
++       */
++      if (unlink(PIDFILE) < 0)
++              close(open(PIDFILE, O_WRONLY|O_CREAT|O_TRUNC, 0644));
++}
++
++static void handlexitsigs(int signum)
++{
++      delpidfile();
++      exit(0);
++}
++
++/* May succeed. If not, won't care. */
++static inline void writepid(uid_t nobody, uid_t nogrp)
++{
++      char buf[24];
++      int fd = open(PIDFILE, O_WRONLY|O_CREAT|O_TRUNC, 0664);
++
++      if (fd < 0)
++              return;
++
++      snprintf(buf, 23, "%d\n", getpid());
++      write(fd, buf, strlen(buf));
++      fchown(fd, nobody, nogrp);
++      close(fd);
++
++      /* should this handle ILL, ... (see signal(7)) */
++      signal(SIGTERM, handlexitsigs);
++      signal(SIGINT,  handlexitsigs);
++      signal(SIGQUIT, handlexitsigs);
++}
++
++/* return 0 as parent, 1 as child */
++static int godaemon(void)
++{
++      uid_t nobody, nogrp;
++      struct passwd *pw;
++
++      switch (fork()) {
++      case -1:
++              bb_perror_msg_and_die("Could not fork");
++
++      case 0:
++              pw = getpwnam(nobodystr);
++              if (pw == NULL)
++                      bb_error_msg_and_die("Cannot find uid/gid of user '%s'", nobodystr);
++              nobody = pw->pw_uid;
++              nogrp = pw->pw_gid;
++              writepid(nobody, nogrp);
++
++              close(0);
++              inetbind();
++              if (setgid(nogrp))   bb_error_msg_and_die("Could not setgid()");
++              if (setegid(nogrp))  bb_error_msg_and_die("Could not setegid()");
++              if (setuid(nobody))  bb_error_msg_and_die("Could not setuid()");
++              if (seteuid(nobody)) bb_error_msg_and_die("Could not seteuid()");
++              close(1);
++              close(2);
++
++              signal(SIGHUP, SIG_IGN);
++              signal(SIGPIPE, SIG_IGN); /* connection closed when writing (raises ???) */
++
++              setsid();
++
++              openlog(bb_applet_name, 0, LOG_DAEMON);
++              return 1;
++      }
++
++      return 0;
++}
++
++static void deleteConn(int s)
++{
++      int i = s - FCS;
++
++      close(s);
++
++      G.conncnt--;
++
++      /*
++       * Most of the time there is 0 connections. Most often that there
++       * is connections, there is just one connection. When this one connection
++       * closes, i == G.conncnt = 0 -> no copying.
++       * When there is more than one connection, the oldest connections closes
++       * earlier on average. When this happens, the code below starts copying
++       * the connection structure w/ highest index to the place which which is
++       * just deleted. This means that the connection structures are no longer
++       * in chronological order. I'd quess this means that when there is more
++       * than 1 connection, on average every other connection structure needs
++       * to be copied over the time all these connections are deleted.
++       */
++      if (i != G.conncnt) {
++              memcpy(&conns[i], &conns[G.conncnt], sizeof(conns[0]));
++              movefd(G.conncnt + FCS, s);
++      }
++
++      FD_CLR(G.conncnt + FCS, &G.readfds);
++}
++
++static int closeOldest(void)
++{
++      time_t min = conns[0].lasttime;
++      int idx = 0;
++      int i;
++
++      for (i = 1; i < MAXCONNS; i++)
++              if (conns[i].lasttime < min)
++                      idx = i;
++
++      replyError(idx + FCS, "X-SERVER-TOO-BUSY");
++      close(idx + FCS);
++
++      return idx;
++}
++
++static int checkInput(char *buf, int len, int l)
++{
++      int i;
++      for (i = len; i < len + l; ++i)
++              if (buf[i] == '\n')
++                      return 1;
++      return 0;
++}
++
++int fakeidentd_main(int argc, char **argv)
++{
++      memset(conns, 0, sizeof(conns));
++      memset(&G, 0, sizeof(G));
++      FD_ZERO(&G.readfds);
++      FD_SET(0, &G.readfds);
++
++      /* handle -b <ip> parameter */
++      bb_getopt_ulflags(argc, argv, "b:", &bind_ip_address);
++      /* handle optional REPLY STRING */
++      if (optind < argc)
++              G.identuser = argv[optind];
++      else
++              G.identuser = nobodystr;
++
++      /* daemonize and have the parent return */
++      if (godaemon() == 0)
++              return 0;
++
++      /* main loop where we process all events and never exit */
++      while (1) {
++      fd_set rfds = G.readfds;
++      struct timeval tv = { 15, 0 };
++      int i;
++      int tim = time(NULL);
++
++      select(G.conncnt + FCS, &rfds, NULL, NULL, G.conncnt? &tv: NULL);
++
++      for (i = G.conncnt - 1; i >= 0; i--) {
++              int s = i + FCS;
++
++              if (FD_ISSET(s, &rfds)) {
++                      char *buf = conns[i].buf;
++                      unsigned int len = conns[i].len;
++                      unsigned int l;
++
++                      if ((l = read(s, buf + len, sizeof(conns[0].buf) - len)) > 0) {
++                              if (checkInput(buf, len, l)) {
++                                      reply(s, buf);
++                                      goto deleteconn;
++                              } else if (len + l >= sizeof(conns[0].buf)) {
++                                      replyError(s, "X-INVALID-REQUEST");
++                                      goto deleteconn;
++                              } else {
++                                      conns[i].len += l;
++                              }
++                      } else {
++                              goto deleteconn;
++                      }
++
++                      conns[i].lasttime = tim;
++                      continue;
++
++deleteconn:
++                      deleteConn(s);
++              } else {
++                      /* implement as time_after() in linux kernel sources ... */
++                      if (conns[i].lasttime + MAXIDLETIME <= tim) {
++                              replyError(s, "X-TIMEOUT");
++                              deleteConn(s);
++                      }
++              }
++      }
++
++      if (FD_ISSET(0, &rfds)) {
++              int s = accept(0, NULL, 0);
++
++              if (s < 0) {
++                      if (errno != EINTR) /* EINTR */
++                              syslog(LOG_ERR, "accept: %s", strerror(errno));
++              } else {
++                      if (G.conncnt == MAXCONNS)
++                              i = closeOldest();
++                      else
++                              i = G.conncnt++;
++
++                      movefd(s, i + FCS); /* move if not already there */
++                      FD_SET(i + FCS, &G.readfds);
++
++                      conns[i].len = 0;
++                      conns[i].lasttime = time(NULL);
++              }
++      }
++      } /* end of while(1) */
++
++      return 0;
++}
++
++static int parseAddrs(char *ptr, char **myaddr, char **heraddr);
++static void reply(int s, char *buf)
++{
++      char *myaddr, *heraddr;
++
++      myaddr = heraddr = NULL;
++
++      if (parseAddrs(buf, &myaddr, &heraddr))
++              replyError(s, "X-INVALID-REQUEST");
++      else {
++              struct iovec iv[6];
++              iv[0].iov_base = myaddr;               iv[0].iov_len = strlen(myaddr);
++              iv[1].iov_base = ", ";                 iv[1].iov_len = 2;
++              iv[2].iov_base = heraddr;              iv[2].iov_len = strlen(heraddr);
++              iv[3].iov_base = (void *)ident_substr; iv[3].iov_len = ident_substr_len;
++              iv[4].iov_base = (void *)G.identuser;  iv[4].iov_len = strlen(G.identuser);
++              iv[5].iov_base = "\r\n";               iv[5].iov_len = 2;
++              writev(s, iv, 6);
++      }
++}
++
++static void replyError(int s, char *buf)
++{
++      struct iovec iv[3];
++      iv[0].iov_base = "0, 0 : ERROR : ";   iv[0].iov_len = 15;
++      iv[1].iov_base = buf;                 iv[1].iov_len = strlen(buf);
++      iv[2].iov_base = "\r\n";              iv[2].iov_len = 2;
++      writev(s, iv, 3);
++}
++
++static int chmatch(char c, char *chars)
++{
++      for (; *chars; chars++)
++              if (c == *chars)
++                      return 1;
++      return 0;
++}
++
++static int skipchars(char **p, char *chars)
++{
++      while (chmatch(**p, chars))
++              (*p)++;
++      if (**p == '\r' || **p == '\n')
++              return 0;
++      return 1;
++}
++
++static int parseAddrs(char *ptr, char **myaddr, char **heraddr)
++{
++      /* parse <port-on-server> , <port-on-client> */
++
++      if (!skipchars(&ptr, " \t"))
++              return -1;
++
++      *myaddr = ptr;
++
++      if (!skipchars(&ptr, "1234567890"))
++              return -1;
++
++      if (!chmatch(*ptr, " \t,"))
++              return -1;
++
++      *ptr++ = '\0';
++
++      if (!skipchars(&ptr, " \t,") )
++              return -1;
++
++      *heraddr = ptr;
++
++      skipchars(&ptr, "1234567890");
++
++      if (!chmatch(*ptr, " \n\r"))
++              return -1;
++
++      *ptr = '\0';
++
++      return 0;
++}
+diff -Nur busybox-1.00/networking/hostname.c busybox/networking/hostname.c
+--- busybox-1.00/networking/hostname.c 2003-07-14 23:21:01.000000000 +0200
++++ busybox/networking/hostname.c      2005-06-04 08:20:05.000000000 +0200
+@@ -1,6 +1,6 @@
+ /* vi: set sw=4 ts=4: */
+ /*
+- * $Id$
++ * $Id$
+  * Mini hostname implementation for busybox
+  *
+  * Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
+diff -Nur busybox-1.00/networking/ifconfig.c busybox/networking/ifconfig.c
+--- busybox-1.00/networking/ifconfig.c 2004-03-31 13:30:08.000000000 +0200
++++ busybox/networking/ifconfig.c      2005-06-04 08:20:05.000000000 +0200
+@@ -15,7 +15,7 @@
+  * Foundation;  either  version 2 of the License, or  (at
+  * your option) any later version.
+  *
+- * $Id$
++ * $Id$
+  *
+  */
+@@ -46,8 +46,8 @@
+ #include <netpacket/packet.h>
+ #include <net/ethernet.h>
+ #else
+-#include <asm/types.h>
+-#include <linux/if_ether.h>
++#include <sys/types.h>
++#include <netinet/if_ether.h>
+ #endif
+ #include "inet_common.h"
+ #include "busybox.h"
+@@ -177,7 +177,7 @@
+ struct arg1opt {
+       const char *name;
+-      unsigned short selector;
++      int selector;
+       unsigned short ifr_offset;
+ };
+diff -Nur busybox-1.00/networking/ifupdown.c busybox/networking/ifupdown.c
+--- busybox-1.00/networking/ifupdown.c 2004-09-14 19:24:58.000000000 +0200
++++ busybox/networking/ifupdown.c      2005-06-04 08:20:05.000000000 +0200
+@@ -150,7 +150,7 @@
+ static char no_act = 0;
+ static char verbose = 0;
+-static char **environ = NULL;
++static char **__myenviron = NULL;
+ #ifdef CONFIG_FEATURE_IFUPDOWN_IP
+@@ -460,7 +460,7 @@
+       { "loopback", loopback_up6, loopback_down6, },
+ };
+-struct address_family_t addr_inet6 = {
++static struct address_family_t addr_inet6 = {
+       "inet6",
+       sizeof(methods6) / sizeof(struct method_t),
+       methods6
+@@ -609,7 +609,7 @@
+       { "loopback", loopback_up, loopback_down, },
+ };
+-struct address_family_t addr_inet =
++static struct address_family_t addr_inet =
+ {
+       "inet",
+       sizeof(methods) / sizeof(struct method_t),
+@@ -961,16 +961,16 @@
+       const int n_env_entries = iface->n_options + 5;
+       char **ppch;
+-      if (environ != NULL) {
+-              for (ppch = environ; *ppch; ppch++) {
++      if (__myenviron != NULL) {
++              for (ppch = __myenviron; *ppch; ppch++) {
+                       free(*ppch);
+                       *ppch = NULL;
+               }
+-              free(environ);
+-              environ = NULL;
++              free(__myenviron);
++              __myenviron = NULL;
+       }
+-      environ = xmalloc(sizeof(char *) * (n_env_entries + 1 /* for final NULL */ ));
+-      environend = environ;
++      __myenviron = xmalloc(sizeof(char *) * (n_env_entries + 1 /* for final NULL */ ));
++      environend = __myenviron;
+       *environend = NULL;
+       for (i = 0; i < iface->n_options; i++) {
+@@ -1010,7 +1010,7 @@
+                       case -1:                /* failure */
+                               return 0;
+                       case 0:         /* child */
+-                              execle(DEFAULT_SHELL, DEFAULT_SHELL, "-c", str, NULL, environ);
++                              execle(DEFAULT_SHELL, DEFAULT_SHELL, "-c", str, NULL, __myenviron);
+                               exit(127);
+               }
+               waitpid(child, &status, 0);
+diff -Nur busybox-1.00/networking/inetd.c busybox/networking/inetd.c
+--- busybox-1.00/networking/inetd.c    2004-06-22 10:40:54.000000000 +0200
++++ busybox/networking/inetd.c 2005-06-04 08:20:05.000000000 +0200
+@@ -560,7 +560,7 @@
+               if (sep != 0) {
+                       int i;
+-#define SWAP(type, a, b) {type c=(type)a; (type)a=(type)b; (type)b=(type)c;}
++#define SWAP(type, a, b) {type c=(type)(a); (a)=(type)(b); (b)=(type)c;}
+                       sigprocmask(SIG_BLOCK, &emptymask, &oldmask);
+                       /*
+diff -Nur busybox-1.00/networking/libiproute/ipaddress.c busybox/networking/libiproute/ipaddress.c
+--- busybox-1.00/networking/libiproute/ipaddress.c     2004-03-15 09:28:56.000000000 +0100
++++ busybox/networking/libiproute/ipaddress.c  2005-06-04 08:20:04.000000000 +0200
+@@ -48,7 +48,7 @@
+       struct rtnl_handle *rth;
+ } filter;
+-void print_link_flags(FILE *fp, unsigned flags, unsigned mdown)
++static void print_link_flags(FILE *fp, unsigned flags, unsigned mdown)
+ {
+       fprintf(fp, "<");
+       flags &= ~IFF_RUNNING;
+diff -Nur busybox-1.00/networking/libiproute/iptunnel.c busybox/networking/libiproute/iptunnel.c
+--- busybox-1.00/networking/libiproute/iptunnel.c      2004-04-26 21:32:49.000000000 +0200
++++ busybox/networking/libiproute/iptunnel.c   2005-06-04 08:20:04.000000000 +0200
+@@ -361,7 +361,7 @@
+       return -1;
+ }
+-int do_del(int argc, char **argv)
++static int do_del(int argc, char **argv)
+ {
+       struct ip_tunnel_parm p;
+@@ -381,7 +381,7 @@
+       return -1;
+ }
+-void print_tunnel(struct ip_tunnel_parm *p)
++static void print_tunnel(struct ip_tunnel_parm *p)
+ {
+       char s1[256];
+       char s2[256];
+diff -Nur busybox-1.00/networking/libiproute/ll_proto.c busybox/networking/libiproute/ll_proto.c
+--- busybox-1.00/networking/libiproute/ll_proto.c      2004-03-15 09:28:56.000000000 +0100
++++ busybox/networking/libiproute/ll_proto.c   2005-06-04 08:20:04.000000000 +0200
+@@ -90,7 +90,7 @@
+ #undef __PF
+-char * ll_proto_n2a(unsigned short id, char *buf, int len)
++const char * ll_proto_n2a(unsigned short id, char *buf, int len)
+ {
+         int i;
+diff -Nur busybox-1.00/networking/libiproute/ll_types.c busybox/networking/libiproute/ll_types.c
+--- busybox-1.00/networking/libiproute/ll_types.c      2003-06-20 11:05:00.000000000 +0200
++++ busybox/networking/libiproute/ll_types.c   2005-06-04 08:20:04.000000000 +0200
+@@ -13,7 +13,7 @@
+ #include <linux/if_arp.h>
+-char * ll_type_n2a(int type, char *buf, int len)
++const char * ll_type_n2a(int type, char *buf, int len)
+ {
+ #define __PF(f,n) { ARPHRD_##f, #n },
+ static struct {
+diff -Nur busybox-1.00/networking/libiproute/rt_names.c busybox/networking/libiproute/rt_names.c
+--- busybox-1.00/networking/libiproute/rt_names.c      2002-12-16 08:37:21.000000000 +0100
++++ busybox/networking/libiproute/rt_names.c   2005-06-04 08:20:04.000000000 +0200
+@@ -76,7 +76,7 @@
+                           rtnl_rtprot_tab, 256);
+ }
+-char * rtnl_rtprot_n2a(int id, char *buf, int len)
++const char * rtnl_rtprot_n2a(int id, char *buf, int len)
+ {
+       if (id<0 || id>=256) {
+               snprintf(buf, len, "%d", id);
+@@ -143,7 +143,7 @@
+                           rtnl_rtscope_tab, 256);
+ }
+-char * rtnl_rtscope_n2a(int id, char *buf, int len)
++const char * rtnl_rtscope_n2a(int id, char *buf, int len)
+ {
+       if (id<0 || id>=256) {
+               snprintf(buf, len, "%d", id);
+@@ -206,7 +206,7 @@
+                           rtnl_rtrealm_tab, 256);
+ }
+-char * rtnl_rtrealm_n2a(int id, char *buf, int len)
++const char * rtnl_rtrealm_n2a(int id, char *buf, int len)
+ {
+       if (id<0 || id>=256) {
+               snprintf(buf, len, "%d", id);
+@@ -272,7 +272,7 @@
+                           rtnl_rttable_tab, 256);
+ }
+-char * rtnl_rttable_n2a(int id, char *buf, int len)
++const char * rtnl_rttable_n2a(int id, char *buf, int len)
+ {
+       if (id<0 || id>=256) {
+               snprintf(buf, len, "%d", id);
+@@ -334,7 +334,7 @@
+                           rtnl_rtdsfield_tab, 256);
+ }
+-char * rtnl_dsfield_n2a(int id, char *buf, int len)
++const char * rtnl_dsfield_n2a(int id, char *buf, int len)
+ {
+       if (id<0 || id>=256) {
+               snprintf(buf, len, "%d", id);
+diff -Nur busybox-1.00/networking/libiproute/utils.c busybox/networking/libiproute/utils.c
+--- busybox-1.00/networking/libiproute/utils.c 2003-03-19 10:12:42.000000000 +0100
++++ busybox/networking/libiproute/utils.c      2005-06-04 08:20:04.000000000 +0200
+@@ -238,7 +238,7 @@
+       return addr.data[0];
+ }
+-void incomplete_command()
++void incomplete_command(void)
+ {
+       bb_error_msg("Command line is not complete. Try option \"help\"");
+       exit(-1);
+diff -Nur busybox-1.00/networking/nameif.c busybox/networking/nameif.c
+--- busybox-1.00/networking/nameif.c   2004-04-25 07:11:17.000000000 +0200
++++ busybox/networking/nameif.c        2005-06-04 08:20:05.000000000 +0200
+@@ -86,7 +86,7 @@
+ }
+ /* Check ascii str_macaddr, convert and copy to *mac */
+-struct ether_addr *cc_macaddr(char *str_macaddr)
++static struct ether_addr *cc_macaddr(char *str_macaddr)
+ {
+       struct ether_addr *lmac, *mac;
+diff -Nur busybox-1.00/networking/nc.c busybox/networking/nc.c
+--- busybox-1.00/networking/nc.c       2004-03-27 11:02:43.000000000 +0100
++++ busybox/networking/nc.c    2005-06-04 08:20:05.000000000 +0200
+@@ -4,7 +4,7 @@
+     0.0.1   6K      It works.
+     0.0.2   5K      Smaller and you can also check the exit condition if you wish.
+-    0.0.3         Uses select()
++    0.0.3           Uses select()
+     19980918 Busy Boxed! Dave Cinege
+     19990512 Uses Select. Charles P. Wright
+@@ -23,13 +23,13 @@
+     You should have received a copy of the GNU General Public License
+     along with this program; if not, write to the Free Software
+     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+-
+ */
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <unistd.h>
++#include <signal.h>
+ #include <sys/types.h>
+ #include <sys/socket.h>
+@@ -40,14 +40,17 @@
+ #include <sys/ioctl.h>
+ #include "busybox.h"
+-#define GAPING_SECURITY_HOLE
++static void timeout(int signum)
++{
++      bb_error_msg_and_die("Timed out");
++}
+ int nc_main(int argc, char **argv)
+ {
+-      int do_listen = 0, lport = 0, delay = 0, tmpfd, opt, sfd, x;
++      int do_listen = 0, lport = 0, delay = 0, wsecs = 0, tmpfd, opt, sfd, x;
+       char buf[BUFSIZ];
+-#ifdef GAPING_SECURITY_HOLE
+-      char * pr00gie = NULL;
++#ifdef CONFIG_NC_GAPING_SECURITY_HOLE
++      char *pr00gie = NULL;
+ #endif
+       struct sockaddr_in address;
+@@ -55,7 +58,7 @@
+       fd_set readfds, testfds;
+-      while ((opt = getopt(argc, argv, "lp:i:e:")) > 0) {
++      while ((opt = getopt(argc, argv, "lp:i:e:w:")) > 0) {
+               switch (opt) {
+                       case 'l':
+                               do_listen++;
+@@ -66,23 +69,25 @@
+                       case 'i':
+                               delay = atoi(optarg);
+                               break;
+-#ifdef GAPING_SECURITY_HOLE
++#ifdef CONFIG_NC_GAPING_SECURITY_HOLE
+                       case 'e':
+                               pr00gie = optarg;
+                               break;
+ #endif
++                      case 'w':
++                              wsecs = atoi(optarg);
++                              break;
+                       default:
+                               bb_show_usage();
+               }
+       }
+-#ifdef GAPING_SECURITY_HOLE
++#ifdef CONFIG_NC_GAPING_SECURITY_HOLE
+       if (pr00gie) {
+               /* won't need stdin */
+-              close (STDIN_FILENO);      
++              close(STDIN_FILENO);      
+       }
+-#endif /* GAPING_SECURITY_HOLE */
+-
++#endif /* CONFIG_NC_GAPING_SECURITY_HOLE */
+       if ((do_listen && optind != argc) || (!do_listen && optind + 2 != argc))
+               bb_show_usage();
+@@ -90,10 +95,15 @@
+       if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+               bb_perror_msg_and_die("socket");
+       x = 1;
+-      if (setsockopt (sfd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof (x)) == -1)
+-              bb_perror_msg_and_die ("reuseaddr failed");
++      if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof (x)) == -1)
++              bb_perror_msg_and_die("reuseaddr");
+       address.sin_family = AF_INET;
++      if (wsecs) {
++              signal(SIGALRM, timeout);
++              alarm(wsecs);
++      }
++
+       if (lport != 0) {
+               memset(&address.sin_addr, 0, sizeof(address.sin_addr));
+               address.sin_port = lport;
+@@ -123,19 +133,23 @@
+                       bb_perror_msg_and_die("connect");
+       }
+-#ifdef GAPING_SECURITY_HOLE
++      if (wsecs) {
++              alarm(0);
++              signal(SIGALRM, SIG_DFL);
++      }
++
++#ifdef CONFIG_NC_GAPING_SECURITY_HOLE
+       /* -e given? */
+       if (pr00gie) {
+               dup2(sfd, 0);
+               close(sfd);
+-              dup2 (0, 1);
+-              dup2 (0, 2);
+-              execl (pr00gie, pr00gie, NULL);
++              dup2(0, 1);
++              dup2(0, 2);
++              execl(pr00gie, pr00gie, NULL);
+               /* Don't print stuff or it will go over the wire.... */
+               _exit(-1);
+       }
+-#endif /* GAPING_SECURITY_HOLE */
+-
++#endif /* CONFIG_NC_GAPING_SECURITY_HOLE */
+       FD_ZERO(&readfds);
+       FD_SET(sfd, &readfds);
+@@ -154,7 +168,7 @@
+               for (fd = 0; fd < FD_SETSIZE; fd++) {
+                       if (FD_ISSET(fd, &testfds)) {
+                               if ((nread = safe_read(fd, buf, sizeof(buf))) < 0)
+-                                      bb_perror_msg_and_die("read");
++                                      bb_perror_msg_and_die(bb_msg_read_error);
+                               if (fd == sfd) {
+                                       if (nread == 0)
+@@ -167,7 +181,7 @@
+                               }
+                               if (bb_full_write(ofd, buf, nread) < 0)
+-                                      bb_perror_msg_and_die("write");
++                                      bb_perror_msg_and_die(bb_msg_write_error);
+                               if (delay > 0) {
+                                       sleep(delay);
+                               }
+diff -Nur busybox-1.00/networking/nslookup.c busybox/networking/nslookup.c
+--- busybox-1.00/networking/nslookup.c 2004-10-13 09:25:01.000000000 +0200
++++ busybox/networking/nslookup.c      2005-06-04 08:20:05.000000000 +0200
+@@ -203,4 +203,4 @@
+       return EXIT_FAILURE;
+ }
+-/* $Id$ */
++/* $Id$ */
+diff -Nur busybox-1.00/networking/ping.c busybox/networking/ping.c
+--- busybox-1.00/networking/ping.c     2004-03-15 09:28:48.000000000 +0100
++++ busybox/networking/ping.c  2005-06-04 08:20:05.000000000 +0200
+@@ -1,6 +1,6 @@
+ /* vi: set sw=4 ts=4: */
+ /*
+- * $Id$
++ * $Id$
+  * Mini ping implementation for busybox
+  *
+  * Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
+@@ -178,7 +178,10 @@
+ static unsigned long tmin = ULONG_MAX, tmax, tsum;
+ static char rcvd_tbl[MAX_DUP_CHK / 8];
+-struct hostent *hostent;
++#ifndef CONFIG_FEATURE_FANCY_PING6
++static
++#endif
++      struct hostent *hostent;
+ static void sendping(int);
+ static void pingstats(int);
+diff -Nur busybox-1.00/networking/ping6.c busybox/networking/ping6.c
+--- busybox-1.00/networking/ping6.c    2004-03-15 09:28:48.000000000 +0100
++++ busybox/networking/ping6.c 2005-06-04 08:20:05.000000000 +0200
+@@ -1,6 +1,6 @@
+ /* vi: set sw=4 ts=4: */
+ /*
+- * $Id$
++ * $Id$
+  * Mini ping implementation for busybox
+  *
+  * Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
+diff -Nur busybox-1.00/networking/route.c busybox/networking/route.c
+--- busybox-1.00/networking/route.c    2004-03-20 00:27:08.000000000 +0100
++++ busybox/networking/route.c 2005-06-04 08:20:05.000000000 +0200
+@@ -15,7 +15,7 @@
+  * Foundation;  either  version 2 of the License, or  (at
+  * your option) any later version.
+  *
+- * $Id$
++ * $Id$
+  *
+  * displayroute() code added by Vladimir N. Oleynik <dzo@simtreas.ru>
+  * adjustments by Larry Doolittle  <LRDoolittle@lbl.gov>
+@@ -485,6 +485,7 @@
+       }
+ }
++/* also used in netstat */
+ void displayroutes(int noresolve, int netstatfmt)
+ {
+       char devname[64], flags[16], sdest[16], sgw[16];
+diff -Nur busybox-1.00/networking/telnetd.c busybox/networking/telnetd.c
+--- busybox-1.00/networking/telnetd.c  2004-09-14 19:24:58.000000000 +0200
++++ busybox/networking/telnetd.c       2005-06-04 08:20:05.000000000 +0200
+@@ -1,4 +1,4 @@
+-/* $Id$
++/* $Id$
+  *
+  * Simple telnet server
+  * Bjorn Wesen, Axis Communications AB (bjornw@axis.com)
+@@ -49,6 +49,15 @@
+ #define BUFSIZE 4000
++#ifdef CONFIG_FEATURE_IPV6
++#define SOCKET_TYPE   AF_INET6
++typedef struct sockaddr_in6 sockaddr_type;
++#else
++#define SOCKET_TYPE   AF_INET
++typedef struct sockaddr_in sockaddr_type;
++#endif
++
++
+ #ifdef CONFIG_LOGIN
+ static const char *loginpath = "/bin/login";
+ #else
+@@ -373,7 +382,7 @@
+ telnetd_main(int argc, char **argv)
+ {
+ #ifndef CONFIG_FEATURE_TELNETD_INETD
+-      struct sockaddr_in sa;
++        sockaddr_type sa;
+       int master_fd;
+ #endif /* CONFIG_FEATURE_TELNETD_INETD */
+       fd_set rdfdset, wrfdset;
+@@ -431,7 +440,7 @@
+       /* Grab a TCP socket.  */
+-      master_fd = socket(AF_INET, SOCK_STREAM, 0);
++        master_fd = socket(SOCKET_TYPE, SOCK_STREAM, 0);
+       if (master_fd < 0) {
+               bb_perror_msg_and_die("socket");
+       }
+@@ -440,8 +449,13 @@
+       /* Set it to listen to specified port.  */
+       memset((void *)&sa, 0, sizeof(sa));
++#ifdef CONFIG_FEATURE_IPV6
++      sa.sin6_family = AF_INET6;
++      sa.sin6_port = htons(portnbr);
++#else
+       sa.sin_family = AF_INET;
+       sa.sin_port = htons(portnbr);
++#endif
+       if (bind(master_fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
+               bb_perror_msg_and_die("bind");
+diff -Nur busybox-1.00/networking/tftp.c busybox/networking/tftp.c
+--- busybox-1.00/networking/tftp.c     2004-09-14 19:24:58.000000000 +0200
++++ busybox/networking/tftp.c  2005-06-04 08:20:05.000000000 +0200
+@@ -71,8 +71,8 @@
+       "No such user"
+ };
+-const int tftp_cmd_get = 1;
+-const int tftp_cmd_put = 2;
++static const int tftp_cmd_get = 1;
++static const int tftp_cmd_put = 2;
+ #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
+diff -Nur busybox-1.00/networking/udhcp/README.udhcpc busybox/networking/udhcp/README.udhcpc
+--- busybox-1.00/networking/udhcp/README.udhcpc        2004-03-15 09:29:00.000000000 +0100
++++ busybox/networking/udhcp/README.udhcpc     2005-06-04 08:20:05.000000000 +0200
+@@ -12,7 +12,8 @@
+ -c, --clientid=CLIENTID         Client identifier
+ -H, --hostname=HOSTNAME         Client hostname
+--h,                           Alias for -H
++-h,                             Alias for -H
++-F, --fqdn=FQDN                 Client fully qualified domain name
+ -f, --foreground                Do not fork after getting lease
+ -b, --background                Fork to background if lease cannot be
+                                 immediately negotiated.
+diff -Nur busybox-1.00/networking/udhcp/clientpacket.c busybox/networking/udhcp/clientpacket.c
+--- busybox-1.00/networking/udhcp/clientpacket.c       2004-04-14 19:51:25.000000000 +0200
++++ busybox/networking/udhcp/clientpacket.c    2005-06-04 08:20:05.000000000 +0200
+@@ -78,6 +78,7 @@
+       memcpy(packet->chaddr, client_config.arp, 6);
+       add_option_string(packet->options, client_config.clientid);
+       if (client_config.hostname) add_option_string(packet->options, client_config.hostname);
++      if (client_config.fqdn) add_option_string(packet->options, client_config.fqdn);
+       add_option_string(packet->options, (uint8_t *) &vendor_id);
+ }
+diff -Nur busybox-1.00/networking/udhcp/dhcpc.c busybox/networking/udhcp/dhcpc.c
+--- busybox-1.00/networking/udhcp/dhcpc.c      2004-05-19 10:29:05.000000000 +0200
++++ busybox/networking/udhcp/dhcpc.c   2005-06-04 08:20:05.000000000 +0200
+@@ -58,17 +58,18 @@
+ struct client_config_t client_config = {
+       /* Default options. */
+-      abort_if_no_lease: 0,
+-      foreground: 0,
+-      quit_after_lease: 0,
+-      background_if_no_lease: 0,
+-      interface: "eth0",
+-      pidfile: NULL,
+-      script: DEFAULT_SCRIPT,
+-      clientid: NULL,
+-      hostname: NULL,
+-      ifindex: 0,
+-      arp: "\0\0\0\0\0\0",            /* appease gcc-3.0 */
++      .abort_if_no_lease = 0,
++      .foreground = 0,
++      .quit_after_lease = 0,
++      .background_if_no_lease = 0,
++      .interface = "eth0",
++      .pidfile = NULL,
++      .script = DEFAULT_SCRIPT,
++      .clientid = NULL,
++      .hostname = NULL,
++      .fqdn = NULL,
++      .ifindex = 0,
++      .arp = "\0\0\0\0\0\0",          /* appease gcc-3.0 */
+ };
+ #ifndef IN_BUSYBOX
+@@ -79,6 +80,7 @@
+ "  -c, --clientid=CLIENTID         Client identifier\n"
+ "  -H, --hostname=HOSTNAME         Client hostname\n"
+ "  -h                              Alias for -H\n"
++"  -F, --fqdn=FQDN                 Client fully qualified domain name\n"
+ "  -f, --foreground                Do not fork after getting lease\n"
+ "  -b, --background                Fork to background if lease cannot be\n"
+ "                                  immediately negotiated.\n"
+@@ -197,7 +199,8 @@
+               {"foreground",  no_argument,            0, 'f'},
+               {"background",  no_argument,            0, 'b'},
+               {"hostname",    required_argument,      0, 'H'},
+-              {"hostname",    required_argument,      0, 'h'},
++              {"hostname",    required_argument,      0, 'h'},
++              {"fqdn",        required_argument,      0, 'F'},
+               {"interface",   required_argument,      0, 'i'},
+               {"now",         no_argument,            0, 'n'},
+               {"pidfile",     required_argument,      0, 'p'},
+@@ -211,7 +214,7 @@
+       /* get options */
+       while (1) {
+               int option_index = 0;
+-              c = getopt_long(argc, argv, "c:fbH:h:i:np:qr:s:v", arg_options, &option_index);
++              c = getopt_long(argc, argv, "c:fbH:h:F:i:np:qr:s:v", arg_options, &option_index);
+               if (c == -1) break;
+               switch (c) {
+@@ -239,6 +242,23 @@
+                       client_config.hostname[OPT_LEN] = len;
+                       strncpy(client_config.hostname + 2, optarg, len);
+                       break;
++              case 'F':
++                      len = strlen(optarg) > 255 ? 255 : strlen(optarg);
++                      if (client_config.fqdn) free(client_config.fqdn);
++                      client_config.fqdn = xmalloc(len + 5);
++                      client_config.fqdn[OPT_CODE] = DHCP_FQDN;
++                      client_config.fqdn[OPT_LEN] = len + 3;
++                      /* Flags: 0000NEOS
++                      S: 1 => Client requests Server to update A RR in DNS as well as PTR
++                      O: 1 => Server indicates to client that DNS has been updated regardless
++                      E: 1 => Name data is DNS format, i.e. <4>host<6>domain<4>com<0> not "host.domain.com"
++                      N: 1 => Client requests Server to not update DNS
++                      */
++                      client_config.fqdn[OPT_LEN + 1] = 0x1;
++                      client_config.fqdn[OPT_LEN + 2] = 0;
++                      client_config.fqdn[OPT_LEN + 3] = 0;
++                      strncpy(client_config.fqdn + 5, optarg, len);
++                      break;
+               case 'i':
+                       client_config.interface =  optarg;
+                       break;
+@@ -419,6 +439,9 @@
+                                       (unsigned long) packet.xid, xid);
+                               continue;
+                       }
++                      /* Ignore packets that aren't for us */
++                      if (memcmp(client_config.arp,packet.chaddr,6))
++                              continue;
+                       if ((message = get_option(&packet, DHCP_MESSAGE_TYPE)) == NULL) {
+                               DEBUG(LOG_ERR, "couldnt get option from packet -- ignoring");
+diff -Nur busybox-1.00/networking/udhcp/dhcpc.h busybox/networking/udhcp/dhcpc.h
+--- busybox-1.00/networking/udhcp/dhcpc.h      2004-01-31 00:45:12.000000000 +0100
++++ busybox/networking/udhcp/dhcpc.h   2005-06-04 08:20:05.000000000 +0200
+@@ -27,6 +27,7 @@
+       char *script;                   /* User script to run at dhcp events */
+       uint8_t *clientid;              /* Optional client id to use */
+       uint8_t *hostname;              /* Optional hostname to use */
++      uint8_t *fqdn;                  /* Optional fully qualified domain name to use */
+       int ifindex;                    /* Index number of the interface to use */
+       uint8_t arp[6];                 /* Our arp address */
+ };
+diff -Nur busybox-1.00/networking/udhcp/dhcpd.h busybox/networking/udhcp/dhcpd.h
+--- busybox-1.00/networking/udhcp/dhcpd.h      2004-10-08 10:49:26.000000000 +0200
++++ busybox/networking/udhcp/dhcpd.h   2005-06-04 08:20:05.000000000 +0200
+@@ -63,6 +63,7 @@
+ #define DHCP_T2                       0x3b
+ #define DHCP_VENDOR           0x3c
+ #define DHCP_CLIENT_ID                0x3d
++#define DHCP_FQDN             0x51
+ #define DHCP_END              0xFF
+diff -Nur busybox-1.00/networking/udhcp/options.c busybox/networking/udhcp/options.c
+--- busybox-1.00/networking/udhcp/options.c    2004-03-15 09:29:01.000000000 +0100
++++ busybox/networking/udhcp/options.c 2005-06-04 08:20:05.000000000 +0200
+@@ -32,7 +32,9 @@
+       {"ipttl",       OPTION_U8,                              0x17},
+       {"mtu",         OPTION_U16,                             0x1a},
+       {"broadcast",   OPTION_IP | OPTION_REQ,                 0x1c},
+-      {"ntpsrv",      OPTION_IP | OPTION_LIST,                0x2a},
++      {"nisdomain",   OPTION_STRING | OPTION_REQ,             0x28},
++      {"nissrv",      OPTION_IP | OPTION_LIST | OPTION_REQ,   0x29},
++      {"ntpsrv",      OPTION_IP | OPTION_LIST | OPTION_REQ,   0x2a},
+       {"wins",        OPTION_IP | OPTION_LIST,                0x2c},
+       {"requestip",   OPTION_IP,                              0x32},
+       {"lease",       OPTION_U32,                             0x33},
+diff -Nur busybox-1.00/networking/udhcp/script.h busybox/networking/udhcp/script.h
+--- busybox-1.00/networking/udhcp/script.h     2002-10-14 23:41:27.000000000 +0200
++++ busybox/networking/udhcp/script.h  2005-06-04 08:20:05.000000000 +0200
+@@ -1,6 +1,6 @@
+ #ifndef _SCRIPT_H
+ #define _SCRIPT_H
+-void run_script(struct dhcpMessage *packet, const char *name);
++extern void run_script(struct dhcpMessage *packet, const char *name);
+ #endif
+diff -Nur busybox-1.00/networking/wget.c busybox/networking/wget.c
+--- busybox-1.00/networking/wget.c     2004-10-08 10:27:40.000000000 +0200
++++ busybox/networking/wget.c  2005-06-04 08:20:05.000000000 +0200
+@@ -117,9 +117,9 @@
+ /*
+  *  Base64-encode character string
+  *  oops... isn't something similar in uuencode.c?
+- *  It would be better to use already existing code
++ *  XXX: It would be better to use already existing code
+  */
+-char *base64enc(unsigned char *p, char *buf, int len) {
++static char *base64enc(unsigned char *p, char *buf, int len) {
+         char al[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+                     "0123456789+/";
+@@ -854,7 +854,7 @@
+  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+  * SUCH DAMAGE.
+  *
+- *    $Id$
++ *    $Id$
+  */
+diff -Nur busybox-1.00/networking/zcip.c busybox/networking/zcip.c
+--- busybox-1.00/networking/zcip.c     1970-01-01 01:00:00.000000000 +0100
++++ busybox/networking/zcip.c  2005-06-04 08:20:05.000000000 +0200
+@@ -0,0 +1,550 @@
++/*
++ * RFC3927 ZeroConf IPv4 Link-Local addressing
++ * (see <http://www.zeroconf.org/>)
++ *
++ * Copyright (C) 2003 by Arthur van Hoff (avh@strangeberry.com)
++ * Copyright (C) 2004 by David Brownell
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ * 02111-1307 USA
++ */
++
++/*
++ * This can build as part of BusyBox or by itself:
++ *
++ *    $(CROSS_COMPILE)cc -Os -Wall -DNO_BUSYBOX -DDEBUG -o zcip zcip.c
++ *
++ * ZCIP just manages the 169.254.*.* addresses.  That network is not
++ * routed at the IP level, though various proxies or bridges can
++ * certainly be used.  Its naming is built over multicast DNS.
++ */
++
++// #define      DEBUG
++
++// TODO:
++// - more real-world usage/testing, especially daemon mode
++// - kernel packet filters to reduce scheduling noise
++// - avoid silent script failures, especially under load...
++// - link status monitoring (restart on link-up; stop on link-down)
++
++#include <errno.h>
++#include <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++#include <syslog.h>
++#include <poll.h>
++#include <time.h>
++#include <unistd.h>
++
++#include <sys/ioctl.h>
++#include <sys/types.h>
++#include <sys/wait.h>
++#include <sys/time.h>
++#include <sys/socket.h>
++
++#include <arpa/inet.h>
++#include <netinet/in.h>
++#include <netinet/ether.h>
++#include <net/ethernet.h>
++#include <net/if.h>
++#include <net/if_arp.h>
++
++#include <linux/if_packet.h>
++#include <linux/sockios.h>
++
++
++struct arp_packet {
++      struct ether_header hdr;
++      // FIXME this part is netinet/if_ether.h "struct ether_arp"
++      struct arphdr arp;
++      struct ether_addr source_addr;
++      struct in_addr source_ip;
++      struct ether_addr target_addr;
++      struct in_addr target_ip;
++} __attribute__ ((__packed__));
++
++/* 169.254.0.0 */
++static const uint32_t LINKLOCAL_ADDR = 0xa9fe0000;
++
++/* protocol timeout parameters, specified in seconds */
++static const unsigned PROBE_WAIT = 1;
++static const unsigned PROBE_MIN = 1;
++static const unsigned PROBE_MAX = 2;
++static const unsigned PROBE_NUM = 3;
++static const unsigned MAX_CONFLICTS = 10;
++static const unsigned RATE_LIMIT_INTERVAL = 60;
++static const unsigned ANNOUNCE_WAIT = 2;
++static const unsigned ANNOUNCE_NUM = 2;
++static const unsigned ANNOUNCE_INTERVAL = 2;
++static const time_t DEFEND_INTERVAL = 10;
++
++static const unsigned char ZCIP_VERSION[] = "0.75 (18 April 2005)";
++static char *prog;
++
++static const struct in_addr null_ip = { 0 };
++static const struct ether_addr null_addr = { {0, 0, 0, 0, 0, 0} };
++
++static int verbose = 0;
++
++#ifdef DEBUG
++
++#define DBG(fmt,args...) \
++      fprintf(stderr, "%s: " fmt , prog , ## args)
++#define VDBG(fmt,args...) do { \
++      if (verbose) fprintf(stderr, "%s: " fmt , prog ,## args); \
++      } while (0)
++#else
++
++#define DBG(fmt,args...) \
++      do { } while (0)
++#define VDBG  DBG
++#endif                                /* DEBUG */
++
++/**
++ * Pick a random link local IP address on 169.254/16, except that
++ * the first and last 256 addresses are reserved.
++ */
++static void
++pick(struct in_addr *ip)
++{
++      unsigned        tmp;
++
++      /* use cheaper math than lrand48() mod N */
++      do {
++              tmp = (lrand48() >> 16) & IN_CLASSB_HOST;
++      } while (tmp > (IN_CLASSB_HOST - 0x0200));
++      ip->s_addr = htonl((LINKLOCAL_ADDR + 0x0100) + tmp);
++}
++
++/**
++ * Broadcast an ARP packet.
++ */
++static int
++arp(int fd, struct sockaddr *saddr, int op,
++      const struct ether_addr *source_addr, struct in_addr source_ip,
++      const struct ether_addr *target_addr, struct in_addr target_ip)
++{
++      struct arp_packet p;
++
++      // ether header
++      p.hdr.ether_type = htons(ETHERTYPE_ARP);
++      memcpy(p.hdr.ether_shost, source_addr, ETH_ALEN);
++      memset(p.hdr.ether_dhost, 0xff, ETH_ALEN);
++
++      // arp request
++      p.arp.ar_hrd = htons(ARPHRD_ETHER);
++      p.arp.ar_pro = htons(ETHERTYPE_IP);
++      p.arp.ar_hln = ETH_ALEN;
++      p.arp.ar_pln = 4;
++      p.arp.ar_op = htons(op);
++      memcpy(&p.source_addr, source_addr, ETH_ALEN);
++      memcpy(&p.source_ip, &source_ip, sizeof (p.source_ip));
++      memcpy(&p.target_addr, target_addr, ETH_ALEN);
++      memcpy(&p.target_ip, &target_ip, sizeof (p.target_ip));
++
++      // send it
++      if (sendto(fd, &p, sizeof (p), 0, saddr, sizeof (*saddr)) < 0) {
++              perror("sendto");
++              return -errno;
++      }
++      return 0;
++}
++
++/**
++ * Run a script.
++ */
++static int
++run(char *script, char *arg, char *intf, struct in_addr *ip)
++{
++      int pid, status;
++      char *why;
++
++      if (script != NULL) {
++              VDBG("%s run %s %s\n", intf, script, arg);
++              if (ip != NULL) {
++                      char *addr = inet_ntoa(*ip);
++                      setenv("ip", addr, 1);
++                      syslog(LOG_INFO, "%s %s %s", arg, intf, addr);
++              }
++
++              pid = vfork();
++              if (pid < 0) {                  // error
++                      why = "vfork";
++                      goto bad;
++              } else if (pid == 0) {          // child
++                      execl(script, script, arg, NULL);
++                      perror("execl");
++                      _exit(EXIT_FAILURE);
++              } 
++
++              if (waitpid(pid, &status, 0) <= 0) {
++                      why = "waitpid";
++                      goto bad;
++              }
++              if (WEXITSTATUS(status) != 0) {
++                      fprintf(stderr, "%s: script %s failed, exit=%d\n",
++                                      prog, script, WEXITSTATUS(status));
++                      return -errno;
++              }
++      }
++      return 0;
++bad:
++      status = -errno;
++      syslog(LOG_ERR, "%s %s, %s error: %s",
++              arg, intf, why, strerror(errno));
++      return status;
++}
++
++#ifndef       NO_BUSYBOX
++#include "busybox.h"
++#endif
++
++/**
++ * Print usage information.
++ */
++static void __attribute__ ((noreturn))
++usage(const char *msg)
++{
++      fprintf(stderr, "%s: %s\n", prog, msg);
++#ifdef        NO_BUSYBOX
++      fprintf(stderr, "Usage: %s [OPTIONS] ifname script\n"
++                      "\t-f              foreground mode (implied by -v)\n"
++                      "\t-q              quit after address (no daemon)\n"
++                      "\t-r 169.254.x.x  request this address first\n"
++                      "\t-v              verbose; show version\n",
++                      prog);
++      exit(0);
++#else
++      bb_show_usage();
++#endif
++}
++
++/**
++ * Return milliseconds of random delay, up to "secs" seconds.
++ */
++static inline unsigned
++ms_rdelay(unsigned secs)
++{
++      return lrand48() % (secs * 1000);
++}
++
++/**
++ * main program
++ */
++int
++main(int argc, char *argv[])
++      __attribute__ ((weak, alias ("zcip_main")));
++
++int zcip_main(int argc, char *argv[])
++{
++      char *intf = NULL;
++      char *script = NULL;
++      int quit = 0;
++      int foreground = 0;
++
++      char *why;
++      struct sockaddr saddr;
++      struct ether_addr addr;
++      struct in_addr ip = { 0 };
++      int fd;
++      int ready = 0;
++      suseconds_t timeout = 0;        // milliseconds
++      time_t defend = 0;
++      unsigned conflicts = 0;
++      unsigned nprobes = 0;
++      unsigned nclaims = 0;
++      int t;
++
++      // parse commandline: prog [options] ifname script
++      prog = argv[0];
++      while ((t = getopt(argc, argv, "fqr:v")) != EOF) {
++              switch (t) {
++              case 'f':
++                      foreground = 1;
++                      continue;
++              case 'q':
++                      quit = 1;
++                      continue;
++              case 'r':
++                      if (inet_aton(optarg, &ip) == 0
++                                      || (ntohl(ip.s_addr) & IN_CLASSB_NET)
++                                              != LINKLOCAL_ADDR) {
++                              usage("invalid link address");
++                      }
++                      continue;
++              case 'v':
++                      if (!verbose)
++                              printf("%s: version %s\n", prog, ZCIP_VERSION);
++                      verbose++;
++                      foreground = 1;
++                      continue;
++              default:
++                      usage("bad option");
++              }
++      }
++      if (optind < argc - 1) {
++              intf = argv[optind++];
++              setenv("interface", intf, 1);
++              script = argv[optind++];
++      }
++      if (optind != argc || !intf)
++              usage("wrong number of arguments");
++      openlog(prog, 0, LOG_DAEMON);
++
++      // initialize the interface (modprobe, ifup, etc)
++      if (run(script, "init", intf, NULL) < 0)
++              return EXIT_FAILURE;
++
++      // initialize saddr
++      memset(&saddr, 0, sizeof (saddr));
++      strncpy(saddr.sa_data, intf, sizeof (saddr.sa_data));
++
++      // open an ARP socket
++      if ((fd = socket(PF_PACKET, SOCK_PACKET, htons(ETH_P_ARP))) < 0) {
++              why = "open";
++fail:
++              foreground = 1;
++              goto bad;
++      }
++      // bind to the interface's ARP socket
++      if (bind(fd, &saddr, sizeof (saddr)) < 0) {
++              why = "bind";
++              goto fail;
++      } else {
++              struct ifreq ifr;
++              short seed[3];
++
++              // get the interface's ethernet address
++              memset(&ifr, 0, sizeof (ifr));
++              strncpy(ifr.ifr_name, intf, sizeof (ifr.ifr_name));
++              if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
++                      why = "get ethernet address";
++                      goto fail;
++              }
++              memcpy(&addr, &ifr.ifr_hwaddr.sa_data, ETH_ALEN);
++
++              // start with some stable ip address, either a function of
++              // the hardware address or else the last address we used.
++              // NOTE: the sequence of addresses we try changes only
++              // depending on when we detect conflicts.
++              memcpy(seed, &ifr.ifr_hwaddr.sa_data, ETH_ALEN);
++              seed48(seed);
++              if (ip.s_addr == 0)
++                      pick(&ip);
++      }
++
++      // FIXME cases to handle:
++      //  - zcip already running!
++      //  - link already has local address... just defend/update
++
++      // daemonize now; don't delay system startup
++      if (!foreground) {
++              if (daemon(0, verbose) < 0) {
++                      why = "daemon";
++                      goto bad;
++              }
++              syslog(LOG_INFO, "start, interface %s", intf);
++      }
++
++      // run the dynamic address negotiation protocol,
++      // restarting after address conflicts:
++      //  - start with some address we want to try
++      //  - short random delay
++      //  - arp probes to see if another host else uses it
++      //  - arp announcements that we're claiming it
++      //  - use it
++      //  - defend it, within limits
++      while (1) {
++              struct pollfd fds[1];
++              struct timeval tv1;
++              struct arp_packet p;
++
++              fds[0].fd = fd;
++              fds[0].events = POLLIN;
++              fds[0].revents = 0;
++
++              // poll, being ready to adjust current timeout 
++              if (timeout > 0) {
++                      gettimeofday(&tv1, NULL);
++                      tv1.tv_usec += (timeout % 1000) * 1000;
++                      while (tv1.tv_usec > 1000000) {
++                              tv1.tv_usec -= 1000000;
++                              tv1.tv_sec++;
++                      }
++                      tv1.tv_sec += timeout / 1000;
++              } else if (timeout == 0) {
++                      timeout = ms_rdelay(PROBE_WAIT);
++                      // FIXME setsockopt(fd, SO_ATTACH_FILTER, ...) to
++                      // make the kernel filter out all packets except
++                      // ones we'd care about.
++              }
++              VDBG("...wait %ld %s nprobes=%d, nclaims=%d\n",
++                              timeout, intf, nprobes, nclaims);
++              switch (poll(fds, 1, timeout)) {
++
++              // timeouts trigger protocol transitions
++              case 0:
++                      // probes
++                      if (nprobes < PROBE_NUM) {
++                              nprobes++;
++                              VDBG("probe/%d %s@%s\n",
++                                              nprobes, intf, inet_ntoa(ip));
++                              (void)arp(fd, &saddr, ARPOP_REQUEST,
++                                              &addr, null_ip,
++                                              &null_addr, ip);
++                              if (nprobes < PROBE_NUM) {
++                                      timeout = PROBE_MIN * 1000;
++                                      timeout += ms_rdelay(PROBE_MAX
++                                                      - PROBE_MIN);
++                              } else
++                                      timeout = ANNOUNCE_WAIT * 1000;
++                      }
++                      // then announcements
++                      else if (nclaims < ANNOUNCE_NUM) {
++                              nclaims++;
++                              VDBG("announce/%d %s@%s\n",
++                                              nclaims, intf, inet_ntoa(ip));
++                              (void)arp(fd, &saddr, ARPOP_REQUEST,
++                                              &addr, ip,
++                                              &addr, ip);
++                              if (nclaims < ANNOUNCE_NUM) {
++                                      timeout = ANNOUNCE_INTERVAL * 1000;
++                              } else {
++                                      // link is ok to use earlier
++                                      run(script, "config", intf, &ip);
++                                      ready = 1;
++                                      conflicts = 0;
++                                      timeout = -1;
++
++                                      // NOTE:  all other exit paths
++                                      // should deconfig ...
++                                      if (quit)
++                                              return EXIT_SUCCESS;
++                                      // FIXME update filters
++                              }
++                      }
++                      break;
++
++              // packets arriving
++              case 1:
++                      // maybe adjust timeout
++                      if (timeout > 0) {
++                              struct timeval tv2;
++
++                              gettimeofday(&tv2, NULL);
++                              if (timercmp(&tv1, &tv2, <)) {
++                                      timeout = -1;
++                              } else {
++                                      timersub(&tv1, &tv2, &tv1);
++                                      timeout = 1000 * tv1.tv_sec
++                                                      + tv1.tv_usec / 1000;
++                              }
++                      }
++                      if ((fds[0].revents & POLLIN) == 0) {
++                              if (fds[0].revents & POLLERR) {
++                                      // FIXME: links routinely go down;
++                                      // this shouldn't necessarily exit.
++                                      fprintf(stderr, "%s %s: poll error\n",
++                                                      prog, intf);
++                                      if (ready) {
++                                              run(script, "deconfig",
++                                                              intf, &ip);
++                                      }
++                                      return EXIT_FAILURE;
++                              }
++                              continue;
++                      }
++                      // read ARP packet
++                      if (recv(fd, &p, sizeof (p), 0) < 0) {
++                              why = "recv";
++                              goto bad;
++                      }
++                      if (p.hdr.ether_type != htons(ETHERTYPE_ARP))
++                              continue;
++
++                      VDBG("%s recv arp type=%d, op=%d,\n",
++                                      intf, ntohs(p.hdr.ether_type),
++                                      ntohs(p.arp.ar_op));
++                      VDBG("\tsource=%s %s\n",
++                                      ether_ntoa(&p.source_addr),
++                                      inet_ntoa(p.source_ip));
++                      VDBG("\ttarget=%s %s\n",
++                                      ether_ntoa(&p.target_addr),
++                                      inet_ntoa(p.target_ip));
++                      if (p.arp.ar_op != htons(ARPOP_REQUEST)
++                                      && p.arp.ar_op != htons(ARPOP_REPLY))
++                              continue;
++
++                      // some cases are always conflicts 
++                      if ((p.source_ip.s_addr == ip.s_addr)
++                                      && (memcmp(&addr, &p.source_addr,
++                                                      ETH_ALEN) != 0)) {
++collision:
++                              VDBG("%s ARP conflict from %s\n", intf,
++                                              ether_ntoa(&p.source_addr));
++                              if (ready) {
++                                      time_t now = time(0);
++
++                                      if ((defend + DEFEND_INTERVAL)
++                                                      < now) {
++                                              defend = now;
++                                              (void)arp(fd, &saddr,
++                                                              ARPOP_REQUEST,
++                                                              &addr, ip,
++                                                              &addr, ip);
++                                              VDBG("%s defend\n", intf);
++                                              timeout = -1;
++                                              continue;
++                                      }
++                                      defend = now;
++                                      ready = 0;
++                                      run(script, "deconfig", intf, &ip);
++                                      // FIXME rm filters: setsockopt(fd,
++                                      // SO_DETACH_FILTER, ...)
++                              }
++                              conflicts++;
++                              if (conflicts >= MAX_CONFLICTS) {
++                                      VDBG("%s ratelimit\n", intf);
++                                      sleep(RATE_LIMIT_INTERVAL);
++                              }
++                              // restart the whole protocol
++                              pick(&ip);
++                              timeout = 0;
++                              nprobes = 0;
++                              nclaims = 0;
++                      }
++                      // two hosts probing one address is a collision too
++                      else if (p.target_ip.s_addr == ip.s_addr
++                                      && nclaims == 0
++                                      && p.arp.ar_op == htons(ARPOP_REQUEST)
++                                      && memcmp(&addr, &p.target_addr,
++                                                      ETH_ALEN) != 0) {
++                              goto collision;
++                      }
++                      break;
++
++              default:
++                      why = "poll";
++                      goto bad;
++              }
++      }
++bad:
++      if (foreground)
++              perror(why);
++      else 
++              syslog(LOG_ERR, "%s %s, %s error: %s",
++                      prog, intf, why, strerror(errno));
++      return EXIT_FAILURE;
++}
+diff -Nur busybox-1.00/patches/ed.patch busybox/patches/ed.patch
+--- busybox-1.00/patches/ed.patch      1970-01-01 01:00:00.000000000 +0100
++++ busybox/patches/ed.patch   2005-06-04 08:20:03.000000000 +0200
+@@ -0,0 +1,1489 @@
++Index: editors/Makefile.in
++===================================================================
++--- editors/Makefile.in       (revision 10144)
+++++ editors/Makefile.in       (working copy)
++@@ -24,8 +24,9 @@
++ srcdir=$(top_srcdir)/editors
++ 
++ EDITOR-y:=
++-EDITOR-$(CONFIG_AWK)    += awk.o
++-EDITOR-$(CONFIG_PATCH)          += patch.o
+++EDITOR-$(CONFIG_AWK)       += awk.o
+++EDITOR-$(CONFIG_ED)        += ed.o
+++EDITOR-$(CONFIG_PATCH)     += patch.o
++ EDITOR-$(CONFIG_SED)       += sed.o
++ EDITOR-$(CONFIG_VI)        += vi.o
++ EDITOR_SRC:= $(EDITOR-y)
++Index: editors/Config.in
++===================================================================
++--- editors/Config.in (revision 10144)
+++++ editors/Config.in (working copy)
++@@ -20,6 +20,12 @@
++        Enable math functions of the Awk programming language.
++        NOTE: This will require libm to be present for linking.
++ 
+++config CONFIG_ED
+++     bool "ed"
+++     default n
+++     help
+++       ed
+++
++ config CONFIG_PATCH
++      bool "patch"
++      default n
++Index: include/usage.h
++===================================================================
++--- include/usage.h   (revision 10151)
+++++ include/usage.h   (working copy)
++@@ -556,6 +561,9 @@
++      "$ echo \"Erik\\nis\\ncool\"\n" \
++      "Erik\\nis\\ncool\n")
++ 
+++#define ed_trivial_usage ""
+++#define ed_full_usage ""
+++
++ #define env_trivial_usage \
++      "[-iu] [-] [name=value]... [command]"
++ #define env_full_usage \
++Index: include/applets.h
++===================================================================
++--- include/applets.h (revision 10151)
+++++ include/applets.h (working copy)
++@@ -179,6 +179,9 @@
++ #ifdef CONFIG_ECHO
++      APPLET(echo, echo_main, _BB_DIR_BIN, _BB_SUID_NEVER)
++ #endif
+++#ifdef CONFIG_ED
+++     APPLET(ed, ed_main, _BB_DIR_BIN, _BB_SUID_NEVER)
+++#endif
++ #if defined(CONFIG_FEATURE_GREP_EGREP_ALIAS)
++      APPLET_NOUSAGE("egrep", grep_main, _BB_DIR_BIN, _BB_SUID_NEVER)
++ #endif
++--- /dev/null 2005-04-24 01:00:01.350003056 -0400
+++++ ed.c      2005-04-24 01:38:51.000000000 -0400
++@@ -0,0 +1,1425 @@
+++/*
+++ * Copyright (c) 2002 by David I. Bell
+++ * Permission is granted to use, distribute, or modify this source,
+++ * provided that this copyright notice remains intact.
+++ *
+++ * The "ed" built-in command (much simplified)
+++ */
+++
+++#include <stdio.h>
+++#include <stdlib.h>
+++#include <unistd.h>
+++#include <fcntl.h>
+++#include <string.h>
+++#include <memory.h>
+++#include <time.h>
+++#include <ctype.h>
+++#include <sys/param.h>
+++#include <malloc.h>
+++#include "busybox.h"
+++
+++#define      USERSIZE        1024    /* max line length typed in by user */
+++#define      INITBUF_SIZE    1024    /* initial buffer size */
+++
+++typedef      int     BOOL;
+++typedef      int     NUM;
+++typedef      int     LEN;
+++
+++typedef struct LINE LINE;
+++struct LINE {
+++     LINE *next;
+++     LINE *prev;
+++     LEN     len;
+++     char data[1];
+++};
+++
+++static LINE lines;
+++static LINE *curLine;
+++static NUM curNum;
+++static NUM lastNum;
+++static NUM marks[26];
+++static BOOL dirty;
+++static char *fileName;
+++static char searchString[USERSIZE];
+++
+++static char *bufBase;
+++static char *bufPtr;
+++static LEN bufUsed;
+++static LEN bufSize;
+++
+++static       void    doCommands(void);
+++static       void    subCommand(const char * cmd, NUM num1, NUM num2);
+++static       BOOL    getNum(const char ** retcp, BOOL * retHaveNum, NUM * retNum);
+++static       BOOL    setCurNum(NUM num);
+++static       BOOL    initEdit(void);
+++static       void    termEdit(void);
+++static       void    addLines(NUM num);
+++static       BOOL    insertLine(NUM num, const char * data, LEN len);
+++static       BOOL    deleteLines(NUM num1, NUM num2);
+++static       BOOL    printLines(NUM num1, NUM num2, BOOL expandFlag);
+++static       BOOL    writeLines(const char * file, NUM num1, NUM num2);
+++static       BOOL    readLines(const char * file, NUM num);
+++static       NUM     searchLines(const char * str, NUM num1, NUM num2);
+++static       LINE *  findLine(NUM num);
+++
+++static LEN findString(const LINE * lp, const char * str, LEN len, LEN offset);
+++
+++int ed_main(int argc, char **argv)
+++{
+++     if (!initEdit())
+++             return EXIT_FAILURE;
+++
+++     if (argc > 1) {
+++             fileName = strdup(argv[1]);
+++
+++             if (fileName == NULL) {
+++                     bb_error_msg("No memory");
+++                     termEdit();
+++                     return EXIT_SUCCESS;
+++             }
+++
+++             if (!readLines(fileName, 1)) {
+++                     termEdit();
+++                     return EXIT_SUCCESS;
+++             }
+++
+++             if (lastNum)
+++                     setCurNum(1);
+++
+++             dirty = FALSE;
+++     }
+++
+++     doCommands();
+++
+++     termEdit();
+++     return EXIT_SUCCESS;
+++}
+++
+++/*
+++ * Read commands until we are told to stop.
+++ */
+++static void doCommands(void)
+++{
+++     const char *    cp;
+++     char *          endbuf;
+++     char *          newname;
+++     int             len;
+++     NUM             num1;
+++     NUM             num2;
+++     BOOL            have1;
+++     BOOL            have2;
+++     char            buf[USERSIZE];
+++
+++     while (TRUE)
+++     {
+++             printf(": ");
+++             fflush(stdout);
+++
+++             if (fgets(buf, sizeof(buf), stdin) == NULL)
+++                     return;
+++
+++             len = strlen(buf);
+++
+++             if (len == 0)
+++                     return;
+++
+++             endbuf = &buf[len - 1];
+++
+++             if (*endbuf != '\n')
+++             {
+++                     bb_error_msg("Command line too long");
+++
+++                     do
+++                     {
+++                             len = fgetc(stdin);
+++                     }
+++                     while ((len != EOF) && (len != '\n'));
+++
+++                     continue;
+++             }
+++
+++             while ((endbuf > buf) && isblank(endbuf[-1]))
+++                     endbuf--;
+++
+++             *endbuf = '\0';
+++
+++             cp = buf;
+++
+++             while (isblank(*cp))
+++                     cp++;
+++
+++             have1 = FALSE;
+++             have2 = FALSE;
+++
+++             if ((curNum == 0) && (lastNum > 0))
+++             {
+++                     curNum = 1;
+++                     curLine = lines.next;
+++             }
+++
+++             if (!getNum(&cp, &have1, &num1))
+++                     continue;
+++
+++             while (isblank(*cp))
+++                     cp++;
+++
+++             if (*cp == ',')
+++             {
+++                     cp++;
+++
+++                     if (!getNum(&cp, &have2, &num2))
+++                             continue;
+++
+++                     if (!have1)
+++                             num1 = 1;
+++
+++                     if (!have2)
+++                             num2 = lastNum;
+++
+++                     have1 = TRUE;
+++                     have2 = TRUE;
+++             }
+++
+++             if (!have1)
+++                     num1 = curNum;
+++
+++             if (!have2)
+++                     num2 = num1;
+++
+++             switch (*cp++)
+++             {
+++                     case 'a':
+++                             addLines(num1 + 1);
+++                             break;
+++
+++                     case 'c':
+++                             deleteLines(num1, num2);
+++                             addLines(num1);
+++                             break;
+++
+++                     case 'd':
+++                             deleteLines(num1, num2);
+++                             break;
+++
+++                     case 'f':
+++                             if (*cp && !isblank(*cp))
+++                             {
+++                                     bb_error_msg("Bad file command");
+++                                     break;
+++                             }
+++
+++                             while (isblank(*cp))
+++                                     cp++;
+++
+++                             if (*cp == '\0')
+++                             {
+++                                     if (fileName)
+++                                             printf("\"%s\"\n", fileName);
+++                                     else
+++                                             printf("No file name\n");
+++
+++                                     break;
+++                             }
+++
+++                             newname = strdup(cp);
+++
+++                             if (newname == NULL)
+++                             {
+++                                     bb_error_msg("No memory for file name");
+++                                     break;
+++                             }
+++
+++                             if (fileName)
+++                                     free(fileName);
+++
+++                             fileName = newname;
+++                             break;
+++
+++                     case 'i':
+++                             addLines(num1);
+++                             break;
+++
+++                     case 'k':
+++                             while (isblank(*cp))
+++                                     cp++;
+++
+++                             if ((*cp < 'a') || (*cp > 'a') || cp[1])
+++                             {
+++                                     bb_error_msg("Bad mark name");
+++                                     break;
+++                             }
+++
+++                             marks[*cp - 'a'] = num2;
+++                             break;
+++
+++                     case 'l':
+++                             printLines(num1, num2, TRUE);
+++                             break;
+++
+++                     case 'p':
+++                             printLines(num1, num2, FALSE);
+++                             break;
+++
+++                     case 'q':
+++                             while (isblank(*cp))
+++                                     cp++;
+++
+++                             if (have1 || *cp)
+++                             {
+++                                     bb_error_msg("Bad quit command");
+++                                     break;
+++                             }
+++
+++                             if (!dirty)
+++                                     return;
+++
+++                             printf("Really quit? ");
+++                             fflush(stdout);
+++
+++                             buf[0] = '\0';
+++                             fgets(buf, sizeof(buf), stdin);
+++                             cp = buf;
+++
+++                             while (isblank(*cp))
+++                                     cp++;
+++
+++                             if ((*cp == 'y') || (*cp == 'Y'))
+++                                     return;
+++
+++                             break;
+++
+++                     case 'r':
+++                             if (*cp && !isblank(*cp))
+++                             {
+++                                     bb_error_msg("Bad read command");
+++                                     break;
+++                             }
+++
+++                             while (isblank(*cp))
+++                                     cp++;
+++
+++                             if (*cp == '\0')
+++                             {
+++                                     bb_error_msg("No file name");
+++                                     break;
+++                             }
+++
+++                             if (!have1)
+++                                     num1 = lastNum;
+++
+++                             if (readLines(cp, num1 + 1))
+++                                     break;
+++
+++                             if (fileName == NULL)
+++                                     fileName = strdup(cp);
+++
+++                             break;
+++
+++                     case 's':
+++                             subCommand(cp, num1, num2);
+++                             break;
+++
+++                     case 'w':
+++                             if (*cp && !isblank(*cp))
+++                             {
+++                                     bb_error_msg("Bad write command");
+++                                     break;
+++                             }
+++
+++                             while (isblank(*cp))
+++                                     cp++;
+++
+++                             if (!have1) {
+++                                     num1 = 1;
+++                                     num2 = lastNum;
+++                             }
+++
+++                             if (*cp == '\0')
+++                                     cp = fileName;
+++
+++                             if (cp == NULL)
+++                             {
+++                                     bb_error_msg("No file name specified");
+++                                     break;
+++                             }
+++     
+++                             writeLines(cp, num1, num2);
+++                             break;
+++
+++                     case 'z':
+++                             switch (*cp)
+++                             {
+++                             case '-':
+++                                     printLines(curNum-21, curNum, FALSE);
+++                                     break;
+++                             case '.':
+++                                     printLines(curNum-11, curNum+10, FALSE);
+++                                     break;
+++                             default:
+++                                     printLines(curNum, curNum+21, FALSE);
+++                                     break;
+++                             }
+++                             break;
+++
+++                     case '.':
+++                             if (have1)
+++                             {
+++                                     bb_error_msg("No arguments allowed");
+++                                     break;
+++                             }
+++
+++                             printLines(curNum, curNum, FALSE);
+++                             break;
+++     
+++                     case '-':
+++                             if (setCurNum(curNum - 1))
+++                                     printLines(curNum, curNum, FALSE);
+++
+++                             break;
+++
+++                     case '=':
+++                             printf("%d\n", num1);
+++                             break;
+++
+++                     case '\0':
+++                             if (have1)
+++                             {
+++                                     printLines(num2, num2, FALSE);
+++                                     break;
+++                             }
+++
+++                             if (setCurNum(curNum + 1))
+++                                     printLines(curNum, curNum, FALSE);
+++
+++                             break;
+++
+++                     default:
+++                             bb_error_msg("Unimplemented command");
+++                             break;
+++             }
+++     }
+++}
+++
+++
+++/*
+++ * Do the substitute command.
+++ * The current line is set to the last substitution done.
+++ */
+++static void
+++subCommand(const char * cmd, NUM num1, NUM num2)
+++{
+++     int     delim;
+++     char *  cp;
+++     char *  oldStr;
+++     char *  newStr;
+++     LEN     oldLen;
+++     LEN     newLen;
+++     LEN     deltaLen;
+++     LEN     offset;
+++     LINE *  lp;
+++     LINE *  nlp;
+++     BOOL    globalFlag;
+++     BOOL    printFlag;
+++     BOOL    didSub;
+++     BOOL    needPrint;
+++     char    buf[USERSIZE];
+++
+++     if ((num1 < 1) || (num2 > lastNum) || (num1 > num2))
+++     {
+++             bb_error_msg("Bad line range for substitute");
+++
+++             return;
+++     }
+++
+++     globalFlag = FALSE;
+++     printFlag = FALSE;
+++     didSub = FALSE;
+++     needPrint = FALSE;
+++
+++     /*
+++      * Copy the command so we can modify it.
+++      */
+++     strcpy(buf, cmd);
+++     cp = buf;
+++
+++     if (isblank(*cp) || (*cp == '\0'))
+++     {
+++             bb_error_msg("Bad delimiter for substitute");
+++
+++             return;
+++     }
+++
+++     delim = *cp++;
+++     oldStr = cp;
+++
+++     cp = strchr(cp, delim);
+++
+++     if (cp == NULL)
+++     {
+++             bb_error_msg("Missing 2nd delimiter for substitute");
+++
+++             return;
+++     }
+++
+++     *cp++ = '\0';
+++
+++     newStr = cp;
+++     cp = strchr(cp, delim);
+++
+++     if (cp)
+++             *cp++ = '\0';
+++     else
+++             cp = "";
+++
+++     while (*cp) switch (*cp++)
+++     {
+++             case 'g':
+++                     globalFlag = TRUE;
+++                     break;
+++
+++             case 'p':
+++                     printFlag = TRUE;
+++                     break;
+++
+++             default:
+++                     bb_error_msg("Unknown option for substitute");
+++
+++                     return;
+++     }
+++
+++     if (*oldStr == '\0')
+++     {
+++             if (searchString[0] == '\0')
+++             {
+++                     bb_error_msg("No previous search string");
+++
+++                     return;
+++             }
+++
+++             oldStr = searchString;
+++     }
+++
+++     if (oldStr != searchString)
+++             strcpy(searchString, oldStr);
+++
+++     lp = findLine(num1);
+++
+++     if (lp == NULL)
+++             return;
+++
+++     oldLen = strlen(oldStr);
+++     newLen = strlen(newStr);
+++     deltaLen = newLen - oldLen;
+++     offset = 0;
+++     nlp = NULL;
+++
+++     while (num1 <= num2)
+++     {
+++             offset = findString(lp, oldStr, oldLen, offset);
+++
+++             if (offset < 0)
+++             {
+++                     if (needPrint)
+++                     {
+++                             printLines(num1, num1, FALSE);
+++                             needPrint = FALSE;
+++                     }
+++
+++                     offset = 0;
+++                     lp = lp->next;
+++                     num1++;
+++
+++                     continue;
+++             }
+++
+++             needPrint = printFlag;
+++             didSub = TRUE;
+++             dirty = TRUE;
+++
+++             /*
+++              * If the replacement string is the same size or shorter
+++              * than the old string, then the substitution is easy.
+++              */
+++             if (deltaLen <= 0)
+++             {
+++                     memcpy(&lp->data[offset], newStr, newLen);
+++
+++                     if (deltaLen)
+++                     {
+++                             memcpy(&lp->data[offset + newLen],
+++                                     &lp->data[offset + oldLen],
+++                                     lp->len - offset - oldLen);
+++
+++                             lp->len += deltaLen;
+++                     }
+++
+++                     offset += newLen;
+++
+++                     if (globalFlag)
+++                             continue;
+++
+++                     if (needPrint)
+++                     {
+++                             printLines(num1, num1, FALSE);
+++                             needPrint = FALSE;
+++                     }
+++
+++                     lp = lp->next;
+++                     num1++;
+++
+++                     continue;
+++             }
+++
+++             /*
+++              * The new string is larger, so allocate a new line
+++              * structure and use that.  Link it in in place of
+++              * the old line structure.
+++              */
+++             nlp = (LINE *) malloc(sizeof(LINE) + lp->len + deltaLen);
+++
+++             if (nlp == NULL)
+++             {
+++                     bb_error_msg("Cannot get memory for line");
+++
+++                     return;
+++             }
+++
+++             nlp->len = lp->len + deltaLen;
+++
+++             memcpy(nlp->data, lp->data, offset);
+++
+++             memcpy(&nlp->data[offset], newStr, newLen);
+++
+++             memcpy(&nlp->data[offset + newLen],
+++                     &lp->data[offset + oldLen],
+++                     lp->len - offset - oldLen);
+++
+++             nlp->next = lp->next;
+++             nlp->prev = lp->prev;
+++             nlp->prev->next = nlp;
+++             nlp->next->prev = nlp;
+++
+++             if (curLine == lp)
+++                     curLine = nlp;
+++
+++             free(lp);
+++             lp = nlp;
+++
+++             offset += newLen;
+++
+++             if (globalFlag)
+++                     continue;
+++
+++             if (needPrint)
+++             {
+++                     printLines(num1, num1, FALSE);
+++                     needPrint = FALSE;
+++             }
+++
+++             lp = lp->next;
+++             num1++;
+++     }
+++
+++     if (!didSub)
+++             bb_error_msg("No substitutions found for \"%s\"", oldStr);
+++}
+++
+++
+++/*
+++ * Search a line for the specified string starting at the specified
+++ * offset in the line.  Returns the offset of the found string, or -1.
+++ */
+++static LEN
+++findString( const LINE * lp, const char * str, LEN len, LEN offset)
+++{
+++     LEN             left;
+++     const char *    cp;
+++     const char *    ncp;
+++
+++     cp = &lp->data[offset];
+++     left = lp->len - offset;
+++
+++     while (left >= len)
+++     {
+++             ncp = memchr(cp, *str, left);
+++
+++             if (ncp == NULL)
+++                     return -1;
+++
+++             left -= (ncp - cp);
+++
+++             if (left < len)
+++                     return -1;
+++
+++             cp = ncp;
+++
+++             if (memcmp(cp, str, len) == 0)
+++                     return (cp - lp->data);
+++
+++             cp++;
+++             left--;
+++     }
+++
+++     return -1;
+++}
+++
+++
+++/*
+++ * Add lines which are typed in by the user.
+++ * The lines are inserted just before the specified line number.
+++ * The lines are terminated by a line containing a single dot (ugly!),
+++ * or by an end of file.
+++ */
+++static void
+++addLines(NUM num)
+++{
+++     int     len;
+++     char    buf[USERSIZE + 1];
+++
+++     while (fgets(buf, sizeof(buf), stdin))
+++     {
+++             if ((buf[0] == '.') && (buf[1] == '\n') && (buf[2] == '\0'))
+++                     return;
+++
+++             len = strlen(buf);
+++
+++             if (len == 0)
+++                     return;
+++
+++             if (buf[len - 1] != '\n')
+++             {
+++                     bb_error_msg("Line too long");
+++
+++                     do
+++                     {
+++                             len = fgetc(stdin);
+++                     }
+++                     while ((len != EOF) && (len != '\n'));
+++
+++                     return;
+++             }
+++
+++             if (!insertLine(num++, buf, len))
+++                     return;
+++     }
+++}
+++
+++
+++/*
+++ * Parse a line number argument if it is present.  This is a sum
+++ * or difference of numbers, '.', '$', 'x, or a search string.
+++ * Returns TRUE if successful (whether or not there was a number). 
+++ * Returns FALSE if there was a parsing error, with a message output.
+++ * Whether there was a number is returned indirectly, as is the number.
+++ * The character pointer which stopped the scan is also returned.
+++ */
+++static BOOL
+++getNum(const char ** retcp, BOOL * retHaveNum, NUM * retNum)
+++{
+++     const char *    cp;
+++     char *          endStr;
+++     char            str[USERSIZE];
+++     BOOL            haveNum;
+++     NUM             value;
+++     NUM             num;
+++     NUM             sign;
+++
+++     cp = *retcp;
+++     haveNum = FALSE;
+++     value = 0;
+++     sign = 1;
+++
+++     while (TRUE)
+++     {
+++             while (isblank(*cp))
+++                     cp++;
+++
+++             switch (*cp)
+++             {
+++                     case '.':
+++                             haveNum = TRUE;
+++                             num = curNum;
+++                             cp++;
+++                             break;
+++
+++                     case '$':
+++                             haveNum = TRUE;
+++                             num = lastNum;
+++                             cp++;
+++                             break;
+++
+++                     case '\'':
+++                             cp++;
+++
+++                             if ((*cp < 'a') || (*cp > 'z'))
+++                             {
+++                                     bb_error_msg("Bad mark name");
+++
+++                                     return FALSE;
+++                             }
+++
+++                             haveNum = TRUE;
+++                             num = marks[*cp++ - 'a'];
+++                             break;
+++
+++                     case '/':
+++                             strcpy(str, ++cp);
+++                             endStr = strchr(str, '/');
+++
+++                             if (endStr)
+++                             {
+++                                     *endStr++ = '\0';
+++                                     cp += (endStr - str);
+++                             }
+++                             else
+++                                     cp = "";
+++
+++                             num = searchLines(str, curNum, lastNum);
+++
+++                             if (num == 0)
+++                                     return FALSE;
+++
+++                             haveNum = TRUE;
+++                             break;
+++
+++                     default:
+++                             if (!isdigit(*cp))
+++                             {
+++                                     *retcp = cp;
+++                                     *retHaveNum = haveNum;
+++                                     *retNum = value;
+++
+++                                     return TRUE;
+++                             }
+++
+++                             num = 0;
+++
+++                             while (isdigit(*cp))
+++                                     num = num * 10 + *cp++ - '0';
+++
+++                             haveNum = TRUE;
+++                             break;
+++             }
+++
+++             value += num * sign;
+++
+++             while (isblank(*cp))
+++                     cp++;
+++
+++             switch (*cp)
+++             {
+++                     case '-':
+++                             sign = -1;
+++                             cp++;
+++                             break;
+++
+++                     case '+':
+++                             sign = 1;
+++                             cp++;
+++                             break;
+++
+++                     default:
+++                             *retcp = cp;
+++                             *retHaveNum = haveNum;
+++                             *retNum = value;
+++
+++                             return TRUE;
+++             }
+++     }
+++}
+++
+++
+++/*
+++ * Initialize everything for editing.
+++ */
+++static BOOL
+++initEdit(void)
+++{
+++     int     i;
+++
+++     bufSize = INITBUF_SIZE;
+++     bufBase = malloc(bufSize);
+++
+++     if (bufBase == NULL)
+++     {
+++             bb_error_msg("No memory for buffer");
+++
+++             return FALSE;
+++     }
+++
+++     bufPtr = bufBase;
+++     bufUsed = 0;
+++
+++     lines.next = &lines;
+++     lines.prev = &lines;
+++
+++     curLine = NULL;
+++     curNum = 0;
+++     lastNum = 0;
+++     dirty = FALSE;
+++     fileName = NULL;
+++     searchString[0] = '\0';
+++
+++     for (i = 0; i < 26; i++)
+++             marks[i] = 0;
+++
+++     return TRUE;
+++}
+++
+++
+++/*
+++ * Finish editing.
+++ */
+++static void
+++termEdit(void)
+++{
+++     if (bufBase)
+++             free(bufBase);
+++
+++     bufBase = NULL;
+++     bufPtr = NULL;
+++     bufSize = 0;
+++     bufUsed = 0;
+++
+++     if (fileName)
+++             free(fileName);
+++
+++     fileName = NULL;
+++
+++     searchString[0] = '\0';
+++
+++     if (lastNum)
+++             deleteLines(1, lastNum);
+++
+++     lastNum = 0;
+++     curNum = 0;
+++     curLine = NULL;
+++}
+++
+++
+++/*
+++ * Read lines from a file at the specified line number.
+++ * Returns TRUE if the file was successfully read.
+++ */
+++static BOOL
+++readLines(const char * file, NUM num)
+++{
+++     int     fd;
+++     int     cc;
+++     LEN     len;
+++     LEN     lineCount;
+++     LEN     charCount;
+++     char *  cp;
+++
+++     if ((num < 1) || (num > lastNum + 1))
+++     {
+++             bb_error_msg("Bad line for read");
+++
+++             return FALSE;
+++     }
+++
+++     fd = open(file, 0);
+++
+++     if (fd < 0)
+++     {
+++             perror(file);
+++
+++             return FALSE;
+++     }
+++
+++     bufPtr = bufBase;
+++     bufUsed = 0;
+++     lineCount = 0;
+++     charCount = 0;
+++     cc = 0;
+++
+++     printf("\"%s\", ", file);
+++     fflush(stdout);
+++
+++     do
+++     {
+++             cp = memchr(bufPtr, '\n', bufUsed);
+++
+++             if (cp)
+++             {
+++                     len = (cp - bufPtr) + 1;
+++
+++                     if (!insertLine(num, bufPtr, len))
+++                     {
+++                             close(fd);
+++
+++                             return FALSE;
+++                     }
+++
+++                     bufPtr += len;
+++                     bufUsed -= len;
+++                     charCount += len;
+++                     lineCount++;
+++                     num++;
+++
+++                     continue;
+++             }
+++
+++             if (bufPtr != bufBase)
+++             {
+++                     memcpy(bufBase, bufPtr, bufUsed);
+++                     bufPtr = bufBase + bufUsed;
+++             }
+++
+++             if (bufUsed >= bufSize)
+++             {
+++                     len = (bufSize * 3) / 2;
+++                     cp = realloc(bufBase, len);
+++
+++                     if (cp == NULL)
+++                     {
+++                             bb_error_msg("No memory for buffer");
+++                             close(fd);
+++
+++                             return FALSE;
+++                     }
+++
+++                     bufBase = cp;
+++                     bufPtr = bufBase + bufUsed;
+++                     bufSize = len;
+++             }
+++
+++             cc = read(fd, bufPtr, bufSize - bufUsed);
+++             bufUsed += cc;
+++             bufPtr = bufBase;
+++
+++     }
+++     while (cc > 0);
+++
+++     if (cc < 0)
+++     {
+++             perror(file);
+++             close(fd);
+++
+++             return FALSE;
+++     }
+++
+++     if (bufUsed)
+++     {
+++             if (!insertLine(num, bufPtr, bufUsed))
+++             {
+++                     close(fd);
+++
+++                     return -1;
+++             }
+++
+++             lineCount++;
+++             charCount += bufUsed;
+++     }
+++
+++     close(fd);
+++
+++     printf("%d lines%s, %d chars\n", lineCount,
+++             (bufUsed ? " (incomplete)" : ""), charCount);
+++
+++     return TRUE;
+++}
+++
+++
+++/*
+++ * Write the specified lines out to the specified file.
+++ * Returns TRUE if successful, or FALSE on an error with a message output.
+++ */
+++static BOOL
+++writeLines(const char * file, NUM num1, NUM num2)
+++{
+++     int     fd;
+++     LINE *  lp;
+++     LEN     lineCount;
+++     LEN     charCount;
+++
+++     if ((num1 < 1) || (num2 > lastNum) || (num1 > num2))
+++     {
+++             bb_error_msg("Bad line range for write");
+++
+++             return FALSE;
+++     }
+++
+++     lineCount = 0;
+++     charCount = 0;
+++
+++     fd = creat(file, 0666);
+++
+++     if (fd < 0) {
+++             perror(file);
+++
+++             return FALSE;
+++     }
+++
+++     printf("\"%s\", ", file);
+++     fflush(stdout);
+++
+++     lp = findLine(num1);
+++
+++     if (lp == NULL)
+++     {
+++             close(fd);
+++
+++             return FALSE;
+++     }
+++
+++     while (num1++ <= num2)
+++     {
+++             if (write(fd, lp->data, lp->len) != lp->len)
+++             {
+++                     perror(file);
+++                     close(fd);
+++
+++                     return FALSE;
+++             }
+++
+++             charCount += lp->len;
+++             lineCount++;
+++             lp = lp->next;
+++     }
+++
+++     if (close(fd) < 0)
+++     {
+++             perror(file);
+++
+++             return FALSE;
+++     }
+++
+++     printf("%d lines, %d chars\n", lineCount, charCount);
+++
+++     return TRUE;
+++}
+++
+++
+++/*
+++ * Print lines in a specified range.
+++ * The last line printed becomes the current line.
+++ * If expandFlag is TRUE, then the line is printed specially to
+++ * show magic characters.
+++ */
+++static BOOL
+++printLines(NUM num1, NUM num2, BOOL expandFlag)
+++{
+++     const LINE *            lp;
+++     const unsigned char *   cp;
+++     int                     ch;
+++     LEN                     count;
+++
+++     if ((num1 < 1) || (num2 > lastNum) || (num1 > num2))
+++     {
+++             bb_error_msg("Bad line range for print");
+++
+++             return FALSE;
+++     }
+++
+++     lp = findLine(num1);
+++
+++     if (lp == NULL)
+++             return FALSE;
+++
+++     while (num1 <= num2)
+++     {
+++             if (!expandFlag)
+++             {
+++                     write(1, lp->data, lp->len);
+++                     setCurNum(num1++);
+++                     lp = lp->next;
+++
+++                     continue;
+++             }
+++
+++             /*
+++              * Show control characters and characters with the
+++              * high bit set specially.
+++              */
+++             cp = lp->data;
+++             count = lp->len;
+++
+++             if ((count > 0) && (cp[count - 1] == '\n'))
+++                     count--;
+++
+++             while (count-- > 0)
+++             {
+++                     ch = *cp++;
+++
+++                     if (ch & 0x80)
+++                     {
+++                             fputs("M-", stdout);
+++                             ch &= 0x7f;
+++                     }
+++
+++                     if (ch < ' ')
+++                     {
+++                             fputc('^', stdout);
+++                             ch += '@';
+++                     }
+++
+++                     if (ch == 0x7f)
+++                     {
+++                             fputc('^', stdout);
+++                             ch = '?';
+++                     }
+++
+++                     fputc(ch, stdout);
+++             }
+++
+++             fputs("$\n", stdout);
+++
+++             setCurNum(num1++);
+++             lp = lp->next;
+++     }
+++
+++     return TRUE;
+++}
+++
+++
+++/*
+++ * Insert a new line with the specified text.
+++ * The line is inserted so as to become the specified line,
+++ * thus pushing any existing and further lines down one.
+++ * The inserted line is also set to become the current line.
+++ * Returns TRUE if successful.
+++ */
+++static BOOL
+++insertLine(NUM num, const char * data, LEN len)
+++{
+++     LINE *  newLp;
+++     LINE *  lp;
+++
+++     if ((num < 1) || (num > lastNum + 1))
+++     {
+++             bb_error_msg("Inserting at bad line number");
+++
+++             return FALSE;
+++     }
+++
+++     newLp = (LINE *) malloc(sizeof(LINE) + len - 1);
+++
+++     if (newLp == NULL) 
+++     {
+++             bb_error_msg("Failed to allocate memory for line");
+++
+++             return FALSE;
+++     }
+++
+++     memcpy(newLp->data, data, len);
+++     newLp->len = len;
+++
+++     if (num > lastNum)
+++             lp = &lines;
+++     else
+++     {
+++             lp = findLine(num);
+++
+++             if (lp == NULL)
+++             {
+++                     free((char *) newLp);
+++
+++                     return FALSE;
+++             }
+++     }
+++
+++     newLp->next = lp;
+++     newLp->prev = lp->prev;
+++     lp->prev->next = newLp;
+++     lp->prev = newLp;
+++
+++     lastNum++;
+++     dirty = TRUE;
+++
+++     return setCurNum(num);
+++}
+++
+++
+++/*
+++ * Delete lines from the given range.
+++ */
+++static BOOL
+++deleteLines(NUM num1, NUM num2)
+++{
+++     LINE *  lp;
+++     LINE *  nlp;
+++     LINE *  plp;
+++     NUM     count;
+++
+++     if ((num1 < 1) || (num2 > lastNum) || (num1 > num2))
+++     {
+++             bb_error_msg("Bad line numbers for delete");
+++
+++             return FALSE;
+++     }
+++
+++     lp = findLine(num1);
+++
+++     if (lp == NULL)
+++             return FALSE;
+++
+++     if ((curNum >= num1) && (curNum <= num2))
+++     {
+++             if (num2 < lastNum)
+++                     setCurNum(num2 + 1);
+++             else if (num1 > 1)
+++                     setCurNum(num1 - 1);
+++             else
+++                     curNum = 0;
+++     }
+++
+++     count = num2 - num1 + 1;
+++
+++     if (curNum > num2)
+++             curNum -= count;
+++
+++     lastNum -= count;
+++
+++     while (count-- > 0)
+++     {
+++             nlp = lp->next;
+++             plp = lp->prev;
+++             plp->next = nlp;
+++             nlp->prev = plp;
+++             lp->next = NULL;
+++             lp->prev = NULL;
+++             lp->len = 0;
+++             free(lp);
+++             lp = nlp;
+++     }
+++
+++     dirty = TRUE;
+++
+++     return TRUE;
+++}
+++
+++
+++/*
+++ * Search for a line which contains the specified string.
+++ * If the string is NULL, then the previously searched for string
+++ * is used.  The currently searched for string is saved for future use.
+++ * Returns the line number which matches, or 0 if there was no match
+++ * with an error printed.
+++ */
+++static NUM
+++searchLines(const char * str, NUM num1, NUM num2)
+++{
+++     const LINE *    lp;
+++     int             len;
+++
+++     if ((num1 < 1) || (num2 > lastNum) || (num1 > num2))
+++     {
+++             bb_error_msg("Bad line numbers for search");
+++
+++             return 0;
+++     }
+++
+++     if (*str == '\0')
+++     {
+++             if (searchString[0] == '\0')
+++             {
+++                     bb_error_msg("No previous search string");
+++
+++                     return 0;
+++             }
+++
+++             str = searchString;
+++     }
+++
+++     if (str != searchString)
+++             strcpy(searchString, str);
+++
+++     len = strlen(str);
+++
+++     lp = findLine(num1);
+++
+++     if (lp == NULL)
+++             return 0;
+++
+++     while (num1 <= num2)
+++     {
+++             if (findString(lp, str, len, 0) >= 0)
+++                     return num1;
+++
+++             num1++;
+++             lp = lp->next;
+++     }
+++
+++     bb_error_msg("Cannot find string \"%s\"", str);
+++
+++     return 0;
+++}
+++
+++
+++/*
+++ * Return a pointer to the specified line number.
+++ */
+++static LINE *
+++findLine(NUM num)
+++{
+++     LINE *  lp;
+++     NUM     lnum;
+++
+++     if ((num < 1) || (num > lastNum))
+++     {
+++             bb_error_msg("Line number %d does not exist", num);
+++
+++             return NULL;
+++     }
+++
+++     if (curNum <= 0)
+++     {
+++             curNum = 1;
+++             curLine = lines.next;
+++     }
+++
+++     if (num == curNum)
+++             return curLine;
+++
+++     lp = curLine;
+++     lnum = curNum;
+++
+++     if (num < (curNum / 2))
+++     {
+++             lp = lines.next;
+++             lnum = 1;
+++     }
+++     else if (num > ((curNum + lastNum) / 2))
+++     {
+++             lp = lines.prev;
+++             lnum = lastNum;
+++     }
+++
+++     while (lnum < num)
+++     {
+++             lp = lp->next;
+++             lnum++;
+++     }
+++
+++     while (lnum > num)
+++     {
+++             lp = lp->prev;
+++             lnum--;
+++     }
+++
+++     return lp;
+++}
+++
+++
+++/*
+++ * Set the current line number.
+++ * Returns TRUE if successful.
+++ */
+++static BOOL
+++setCurNum(NUM num)
+++{
+++     LINE *  lp;
+++
+++     lp = findLine(num);
+++
+++     if (lp == NULL)
+++             return FALSE;
+++
+++     curNum = num;
+++     curLine = lp;
+++
+++     return TRUE;
+++}
+++
+++/* END CODE */
+diff -Nur busybox-1.00/patches/eject.diff busybox/patches/eject.diff
+--- busybox-1.00/patches/eject.diff    2004-03-15 09:29:02.000000000 +0100
++++ busybox/patches/eject.diff 1970-01-01 01:00:00.000000000 +0100
+@@ -1,164 +0,0 @@
+-Index: AUTHORS
+-===================================================================
+-RCS file: /var/cvs/busybox/AUTHORS,v
+-retrieving revision 1.40
+-diff -u -r1.40 AUTHORS
+---- a/AUTHORS 9 Oct 2003 21:19:21 -0000       1.40
+-+++ b/AUTHORS 5 Mar 2004 07:23:17 -0000
+-@@ -8,6 +8,9 @@
+-
+- -----------
+-
+-+Peter Willis <psyphreak@phreaker.net>
+-+    eject
+-+
+- Emanuele Aina <emanuele.aina@tiscali.it>
+-      run-parts
+-
+-Index: coreutils/Config.in
+-===================================================================
+-RCS file: /var/cvs/busybox/coreutils/Config.in,v
+-retrieving revision 1.23
+-diff -u -r1.23 Config.in
+---- a/coreutils/Config.in     5 Mar 2004 06:47:25 -0000       1.23
+-+++ b/coreutils/Config.in     5 Mar 2004 07:23:18 -0000
+-@@ -164,6 +164,13 @@
+-        a command; without options it displays the current
+-        environment.
+-
+-+config CONFIG_EJECT
+-+     bool "eject"
+-+     default n
+-+     help
+-+       ejects a cdrom drive.
+-+       defaults to /dev/cdrom
+-+
+- config CONFIG_EXPR
+-      bool "expr"
+-      default n
+-Index: coreutils/Makefile.in
+-===================================================================
+-RCS file: /var/cvs/busybox/coreutils/Makefile.in,v
+-retrieving revision 1.8
+-diff -u -r1.8 Makefile.in
+---- a/coreutils/Makefile.in   27 Jan 2004 09:22:20 -0000      1.8
+-+++ b/coreutils/Makefile.in   5 Mar 2004 07:23:18 -0000
+-@@ -41,6 +41,7 @@
+- COREUTILS-$(CONFIG_DU)       += du.o
+- COREUTILS-$(CONFIG_ECHO)     += echo.o
+- COREUTILS-$(CONFIG_ENV)      += env.o
+-+COREUTILS-$(CONFIG_EJECT)            += eject.o
+- COREUTILS-$(CONFIG_EXPR)     += expr.o
+- COREUTILS-$(CONFIG_FALSE)    += false.o
+- COREUTILS-$(CONFIG_FOLD)     += fold.o
+-Index: coreutils/eject.c
+-===================================================================
+-RCS file: coreutils/eject.c
+-diff -N coreutils/eject.c
+---- /dev/null 1 Jan 1970 00:00:00 -0000
+-+++ b/coreutils/eject.c       5 Mar 2004 07:23:21 -0000
+-@@ -0,0 +1,66 @@
+-+/*
+-+ * eject implementation for busybox
+-+ *
+-+ * Copyright (C) 2004  Peter Willis <psyphreak@phreaker.net>
+-+ *
+-+ * This program is free software; you can redistribute it and/or modify
+-+ * it under the terms of the GNU General Public License as published by
+-+ * the Free Software Foundation; either version 2 of the License, or
+-+ * (at your option) any later version.
+-+ *
+-+ * This program is distributed in the hope that it will be useful,
+-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+-+ * General Public License for more details.
+-+ *
+-+ * You should have received a copy of the GNU General Public License
+-+ * along with this program; if not, write to the Free Software
+-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-+ *
+-+ */
+-+
+-+/*
+-+ * This is a simple hack of eject based on something Erik posted in #uclibc.
+-+ * Most of the dirty work blatantly ripped off from cat.c =)
+-+ */
+-+
+-+#include <stdio.h>
+-+#include <string.h>
+-+#include <sys/types.h>
+-+#include <sys/stat.h>
+-+#include <fcntl.h>
+-+#include <sys/ioctl.h>
+-+#include "busybox.h"
+-+#include <linux/cdrom.h> // needs to be after busybox.h or compile problems arise
+-+
+-+#define DEFAULT_CDROM "/dev/cdrom"
+-+
+-+extern int eject_main(int argc, char **argv)
+-+{
+-+     int fd;
+-+     int flag = CDROMEJECT;
+-+     int i = 1;
+-+     char *device = NULL;
+-+
+-+     /*
+-+      * i'm too lazy to learn bb_getopt_ulflags and this is obscenely large
+-+      * for just some argument parsing so mjn3 can clean it up later.
+-+      * sorry, but PlumpOS 7.0-pre2 needs this asap :-/
+-+      */
+-+     while (++i <= argc) {
+-+             if ( (! strncmp(argv[i-1],"-t",2)) || (! strncmp(argv[i-1],"--trayclose",11)) ) {
+-+                     flag = CDROMCLOSETRAY;
+-+             } else {
+-+                     device = argv[i-1];
+-+             }
+-+     }
+-+     if ( (fd = open(device == NULL ? DEFAULT_CDROM : device, O_RDONLY | O_NONBLOCK) ) < 0 ) {
+-+             perror("eject: Can't open device");
+-+             return(EXIT_FAILURE);
+-+     }
+-+     if (ioctl(fd, flag)) {
+-+             perror("eject: Can't eject cdrom");
+-+             return(EXIT_FAILURE);
+-+     }
+-+     return EXIT_SUCCESS;
+-+}
+-Index: include/applets.h
+-===================================================================
+-RCS file: /var/cvs/busybox/include/applets.h,v
+-retrieving revision 1.111
+-diff -u -r1.111 applets.h
+---- a/include/applets.h       27 Jan 2004 09:22:20 -0000      1.111
+-+++ b/include/applets.h       5 Mar 2004 07:23:21 -0000
+-@@ -178,6 +178,9 @@
+- #if defined(CONFIG_FEATURE_GREP_EGREP_ALIAS)
+-      APPLET_NOUSAGE("egrep", grep_main, _BB_DIR_BIN, _BB_SUID_NEVER)
+- #endif
+-+#ifdef CONFIG_EJECT
+-+     APPLET(eject, eject_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
+-+#endif
+- #ifdef CONFIG_ENV
+-      APPLET(env, env_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
+- #endif
+-Index: include/usage.h
+-===================================================================
+-RCS file: /var/cvs/busybox/include/usage.h,v
+-retrieving revision 1.191
+-diff -u -r1.191 usage.h
+---- a/include/usage.h 25 Feb 2004 10:35:55 -0000      1.191
+-+++ b/include/usage.h 5 Mar 2004 07:23:29 -0000
+-@@ -537,6 +537,13 @@
+-      "\t-, -i\tstart with an empty environment\n" \
+-      "\t-u\tremove variable from the environment\n"
+-
+-+#define eject_trivial_usage \
+-+     "[-t] [FILE]"
+-+#define eject_full_usage \
+-+     "Ejects the specified FILE or /dev/cdrom if FILE is unspecified.\n\n" \
+-+     "Options:\n" \
+-+     "\t-t, --trayclose \tclose tray\n"
+-+
+- #define expr_trivial_usage \
+-      "EXPRESSION"
+- #define expr_full_usage \
+diff -Nur busybox-1.00/procps/ps.c busybox/procps/ps.c
+--- busybox-1.00/procps/ps.c   2004-03-15 09:29:03.000000000 +0100
++++ busybox/procps/ps.c        2005-06-04 08:20:20.000000000 +0200
+@@ -31,9 +31,7 @@
+ #include <sys/ioctl.h>
+ #include "busybox.h"
+ #ifdef CONFIG_SELINUX
+-#include <fs_secure.h>
+-#include <ss.h>
+-#include <flask_util.h>          /* for is_flask_enabled() */
++#include <selinux/selinux.h>  /* for is_selinux_enabled()  */
+ #endif
+ static const int TERMINAL_WIDTH = 79;      /* not 80 in case terminal has linefold bug */
+@@ -48,8 +46,8 @@
+ #ifdef CONFIG_SELINUX
+       int use_selinux = 0;
+-      security_id_t sid;
+-      if(is_flask_enabled() && argv[1] && !strcmp(argv[1], "-c") )
++      security_context_t sid=NULL;
++      if(is_selinux_enabled() && argv[1] && !strcmp(argv[1], "-c") )
+               use_selinux = 1;
+ #endif
+@@ -58,34 +56,42 @@
+       terminal_width--;
+ #ifdef CONFIG_SELINUX
+-      if(use_selinux)
+-              printf("  PID Context                          Stat Command\n");
++      if (use_selinux)
++        printf("  PID Context                          Stat Command\n");
+       else
+ #endif
+-      printf("  PID  Uid     VmSize Stat Command\n");
+-#ifdef CONFIG_SELINUX
+-      while ((p = procps_scan(1, use_selinux, &sid)) != 0) {
+-#else
+-      while ((p = procps_scan(1)) != 0) {
+-#endif
+-              char *namecmd = p->cmd;
++        printf("  PID  Uid     VmSize Stat Command\n");
++      while ((p = procps_scan(1)) != 0)  {
++              char *namecmd = p->cmd;
+ #ifdef CONFIG_SELINUX
+-              if(use_selinux)
+-              {
++              if ( use_selinux )
++                {
+                       char sbuf[128];
+                       len = sizeof(sbuf);
+-                      if(security_sid_to_context(sid, (security_context_t)&sbuf, &len))
+-                              strcpy(sbuf, "unknown");
++                      if (is_selinux_enabled()) {
++                        if (getpidcon(p->pid,&sid)<0)
++                          sid=NULL;
++                      }
++
++                      if (sid) {
++                        /*  I assume sid initilized with NULL  */
++                        len = strlen(sid)+1;
++                        safe_strncpy(sbuf, sid, len);
++                        freecon(sid);
++                        sid=NULL;
++                      }else {
++                        safe_strncpy(sbuf, "unknown",7);
++                      }
+                       len = printf("%5d %-32s %s ", p->pid, sbuf, p->state);
+-              }
++              } 
+               else
+ #endif
+-              if(p->rss == 0)
+-                      len = printf("%5d %-8s        %s ", p->pid, p->user, p->state);
+-              else
+-                      len = printf("%5d %-8s %6ld %s ", p->pid, p->user, p->rss, p->state);
++                if(p->rss == 0)
++                  len = printf("%5d %-8s        %s ", p->pid, p->user, p->state);
++                else
++                  len = printf("%5d %-8s %6ld %s ", p->pid, p->user, p->rss, p->state);
+               i = terminal_width-len;
+               if(namecmd != 0 && namecmd[0] != 0) {
+diff -Nur busybox-1.00/procps/renice.c busybox/procps/renice.c
+--- busybox-1.00/procps/renice.c       2004-03-15 09:29:03.000000000 +0100
++++ busybox/procps/renice.c    2005-06-04 08:20:20.000000000 +0200
+@@ -1,8 +1,8 @@
++/* vi: set sw=4 ts=4: */
+ /*
+- * Mini renice implementation for busybox
++ * renice implementation for busybox
+  *
+- *
+- * Copyright (C) 2000 Dave 'Kill a Cop' Cinege <dcinege@psychosis.com>
++ * Copyright (C) 2005  Manuel Novoa III  <mjn3@codepoet.org>
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -20,35 +20,133 @@
+  *
+  */
++/* Notes:
++ *   Setting an absolute priority was obsoleted in SUSv2 and removed
++ *   in SUSv3.  However, the common linux version of renice does
++ *   absolute and not relative.  So we'll continue supporting absolute,
++ *   although the stdout logging has been removed since both SUSv2 and
++ *   SUSv3 specify that stdout isn't used.
++ *
++ *   This version is lenient in that it doesn't require any IDs.  The
++ *   options -p, -g, and -u are treated as mode switches for the
++ *   following IDs (if any).  Multiple switches are allowed.
++ */
++
+ #include <stdio.h>
+-#include <errno.h>
+ #include <stdlib.h>
++#include <string.h>
++#include <limits.h>
++#include <errno.h>
++#include <unistd.h>
+ #include <sys/time.h>
+ #include <sys/resource.h>
+ #include "busybox.h"
++#if (PRIO_PROCESS < CHAR_MIN) || (PRIO_PROCESS > CHAR_MAX)
++#error Assumption violated : PRIO_PROCESS value
++#endif
++#if (PRIO_PGRP < CHAR_MIN) || (PRIO_PGRP > CHAR_MAX)
++#error Assumption violated : PRIO_PGRP value
++#endif
++#if (PRIO_USER < CHAR_MIN) || (PRIO_USER > CHAR_MAX)
++#error Assumption violated : PRIO_USER value
++#endif
+-extern int renice_main(int argc, char **argv)
++static inline int int_add_no_wrap(int a, int b)
+ {
+-      int prio, status = EXIT_SUCCESS;
++      int s = a + b;
++
++      if (b < 0) {
++              if (s > a) s = INT_MIN;
++      } else {
++              if (s < a) s = INT_MAX;
++      }
++
++      return s;
++}
+-      if (argc < 3)   bb_show_usage();
++int renice_main(int argc, char **argv)
++{
++      static const char Xetpriority_msg[] = "%d : %cetpriority";
+-      prio = atoi(*++argv);
+-      if (prio > 20)          prio = 20;
+-      if (prio < -20)         prio = -20;
++      int retval = EXIT_SUCCESS;
++      int which = PRIO_PROCESS;       /* Default 'which' value. */
++      int use_relative = 0;
++      int adjustment, new_priority;
++      id_t who;
++
++      ++argv;
++
++      /* Check if we are using a relative adjustment. */
++      if (argv[0] && (argv[0][0] == '-') && (argv[0][1] == 'n') && !argv[0][2]) {
++              use_relative = 1;
++              ++argv;
++      }
++
++      if (!*argv) {                           /* No args?  Then show usage. */
++              bb_show_usage();
++      }
++
++      /* Get the priority adjustment (absolute or relative). */
++      adjustment = bb_xgetlarg(*argv, 10, INT_MIN, INT_MAX);
+       while (*++argv) {
+-              int ps = atoi(*argv);
+-              int oldp = getpriority(PRIO_PROCESS, ps);
++              /* Check for a mode switch. */
++              if ((argv[0][0] == '-') && argv[0][1] && !argv[0][2]) {
++                      static const char opts[]
++                              = { 'p', 'g', 'u', 0, PRIO_PROCESS, PRIO_PGRP, PRIO_USER };
++                      const char *p;
++                      if ((p = strchr(opts, argv[0][1]))) {
++                              which = p[4];
++                              continue;
++                      }
++              }
+-              if (setpriority(PRIO_PROCESS, ps, prio) == 0) {
+-                      printf("%d: old priority %d, new priority %d\n", ps, oldp, prio );
++              /* Process an ID arg. */
++              if (which == PRIO_USER) {
++                      struct passwd *p;
++                      if (!(p = getpwnam(*argv))) {
++                              bb_error_msg("unknown user: %s", *argv);
++                              goto HAD_ERROR;
++                      }
++                      who = p->pw_uid;
+               } else {
+-                      bb_perror_msg("%d: setpriority", ps);
+-                      status = EXIT_FAILURE;
++                      char *e;
++                      errno = 0;
++                      who = strtoul(*argv, &e, 10);
++                      if (*e || (*argv == e) || errno) {
++                              bb_error_msg("bad value: %s", *argv);
++                              goto HAD_ERROR;
++                      }
+               }
++
++              /* Get priority to use, and set it. */
++              if (use_relative) {
++                      int old_priority;
++
++                      errno = 0;       /* Needed for getpriority error detection. */
++                      old_priority = getpriority(which, who);
++                      if (errno) {
++                              bb_perror_msg(Xetpriority_msg, who, 'g');
++                              goto HAD_ERROR;
++                      }
++
++                      new_priority = int_add_no_wrap(old_priority, adjustment);
++              } else {
++                      new_priority = adjustment;
++              }
++
++              if (setpriority(which, who, new_priority) == 0) {
++                      continue;
++              }
++
++              bb_perror_msg(Xetpriority_msg, who, 's');
++      HAD_ERROR:
++              retval = EXIT_FAILURE;
+       }
+-      return status;
++      /* No need to check for errors outputing to stderr since, if it
++       * was used, the HAD_ERROR label was reached and retval was set. */
++
++      return retval;
+ }
+diff -Nur busybox-1.00/procps/top.c busybox/procps/top.c
+--- busybox-1.00/procps/top.c  2004-09-14 21:14:00.000000000 +0200
++++ busybox/procps/top.c       2005-06-04 08:20:20.000000000 +0200
+@@ -78,7 +78,7 @@
+     return (int)((Q->stime + Q->utime) - (P->stime + P->utime));
+ }
+-int mult_lvl_cmp(void* a, void* b) {
++static int mult_lvl_cmp(void* a, void* b) {
+     int i, cmp_val;
+     for(i = 0; i < sort_depth; i++) {
+@@ -510,11 +510,7 @@
+               /* read process IDs & status for all the processes */
+               procps_status_t * p;
+-#ifdef CONFIG_SELINUX
+-              while ((p = procps_scan(0, 0, NULL) ) != 0) {
+-#else
+               while ((p = procps_scan(0)) != 0) {
+-#endif
+                       int n = ntop;
+                       top = xrealloc(top, (++ntop)*sizeof(procps_status_t));
+diff -Nur busybox-1.00/scripts/config/Makefile busybox/scripts/config/Makefile
+--- busybox-1.00/scripts/config/Makefile       2004-10-08 09:45:49.000000000 +0200
++++ busybox/scripts/config/Makefile    2005-06-04 08:20:03.000000000 +0200
+@@ -9,7 +9,11 @@
+ all: ncurses conf mconf
++ifeq ($(shell uname),SunOS)
++LIBS = -lcurses
++else
+ LIBS = -lncurses
++endif
+ ifeq (/usr/include/ncurses/ncurses.h, $(wildcard /usr/include/ncurses/ncurses.h))
+       HOSTNCURSES += -I/usr/include/ncurses -DCURSES_LOC="<ncurses.h>"
+ else
+@@ -32,14 +36,17 @@
+ endif
+ endif
+-CONF_SRC  =conf.c
+-MCONF_SRC =mconf.c checklist.c menubox.c textbox.c yesno.c inputbox.c util.c msgbox.c
+-SHARED_SRC=zconf.tab.c
+-SHARED_DEPS:=$(srcdir)/lkc.h $(srcdir)/lkc_proto.h \
+-  lkc_defs.h $(srcdir)/expr.h zconf.tab.h
+-CONF_OBJS =$(patsubst %.c,%.o, $(CONF_SRC))
+-MCONF_OBJS=$(patsubst %.c,%.o, $(MCONF_SRC))
+-SHARED_OBJS=$(patsubst %.c,%.o, $(SHARED_SRC))
++CONF_SRC     = conf.c
++MCONF_SRC    = mconf.c
++LXD_SRC      = lxdialog/checklist.c lxdialog/menubox.c lxdialog/textbox.c \
++               lxdialog/yesno.c lxdialog/inputbox.c lxdialog/util.c \
++               lxdialog/msgbox.c
++SHARED_SRC   = zconf.tab.c
++SHARED_DEPS := $(srcdir)/lkc.h $(srcdir)/lkc_proto.h \
++               lkc_defs.h $(srcdir)/expr.h zconf.tab.h
++CONF_OBJS    = $(patsubst %.c,%.o, $(CONF_SRC))
++MCONF_OBJS   = $(patsubst %.c,%.o, $(MCONF_SRC) $(LXD_SRC))
++SHARED_OBJS  = $(patsubst %.c,%.o, $(SHARED_SRC))
+ conf: $(CONF_OBJS) $(SHARED_OBJS)
+       $(HOSTCC) $(NATIVE_LDFLAGS) $^ -o $@
+diff -Nur busybox-1.00/scripts/config/checklist.c busybox/scripts/config/checklist.c
+--- busybox-1.00/scripts/config/checklist.c    2004-07-15 08:01:05.000000000 +0200
++++ busybox/scripts/config/checklist.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,372 +0,0 @@
+-/*
+- *  checklist.c -- implements the checklist box
+- *
+- *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+- *     Stuart Herbert - S.Herbert@sheffield.ac.uk: radiolist extension
+- *     Alessandro Rubini - rubini@ipvvis.unipv.it: merged the two
+- *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+- *
+- *  This program is free software; you can redistribute it and/or
+- *  modify it under the terms of the GNU General Public License
+- *  as published by the Free Software Foundation; either version 2
+- *  of the License, or (at your option) any later version.
+- *
+- *  This program is distributed in the hope that it will be useful,
+- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- *  GNU General Public License for more details.
+- *
+- *  You should have received a copy of the GNU General Public License
+- *  along with this program; if not, write to the Free Software
+- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+- */
+-
+-#include "dialog.h"
+-
+-static int list_width, check_x, item_x, checkflag;
+-
+-/*
+- * Print list item
+- */
+-static void
+-print_item (WINDOW * win, const char *item, int status,
+-          int choice, int selected)
+-{
+-    int i;
+-
+-    /* Clear 'residue' of last item */
+-    wattrset (win, menubox_attr);
+-    wmove (win, choice, 0);
+-    for (i = 0; i < list_width; i++)
+-      waddch (win, ' ');
+-
+-    wmove (win, choice, check_x);
+-    wattrset (win, selected ? check_selected_attr : check_attr);
+-    if (checkflag == FLAG_CHECK)
+-      wprintw (win, "[%c]", status ? 'X' : ' ');
+-    else
+-      wprintw (win, "(%c)", status ? 'X' : ' ');
+-
+-    wattrset (win, selected ? tag_selected_attr : tag_attr);
+-    mvwaddch(win, choice, item_x, item[0]);
+-    wattrset (win, selected ? item_selected_attr : item_attr);
+-    waddstr (win, (char *)item+1);
+-    if (selected) {
+-      wmove (win, choice, check_x+1);
+-      wrefresh (win);
+-    }
+-}
+-
+-/*
+- * Print the scroll indicators.
+- */
+-static void
+-print_arrows (WINDOW * win, int choice, int item_no, int scroll,
+-              int y, int x, int height)
+-{
+-    wmove(win, y, x);
+-
+-    if (scroll > 0) {
+-      wattrset (win, uarrow_attr);
+-      waddch (win, ACS_UARROW);
+-      waddstr (win, "(-)");
+-    }
+-    else {
+-      wattrset (win, menubox_attr);
+-      waddch (win, ACS_HLINE);
+-      waddch (win, ACS_HLINE);
+-      waddch (win, ACS_HLINE);
+-      waddch (win, ACS_HLINE);
+-    }
+-
+-   y = y + height + 1;
+-   wmove(win, y, x);
+-
+-   if ((height < item_no) && (scroll + choice < item_no - 1)) {
+-      wattrset (win, darrow_attr);
+-      waddch (win, ACS_DARROW);
+-      waddstr (win, "(+)");
+-    }
+-    else {
+-      wattrset (win, menubox_border_attr);
+-      waddch (win, ACS_HLINE);
+-      waddch (win, ACS_HLINE);
+-      waddch (win, ACS_HLINE);
+-      waddch (win, ACS_HLINE);
+-   }
+-}
+-
+-/*
+- *  Display the termination buttons
+- */
+-static void
+-print_buttons( WINDOW *dialog, int height, int width, int selected)
+-{
+-    int x = width / 2 - 11;
+-    int y = height - 2;
+-
+-    print_button (dialog, "Select", y, x, selected == 0);
+-    print_button (dialog, " Help ", y, x + 14, selected == 1);
+-
+-    wmove(dialog, y, x+1 + 14*selected);
+-    wrefresh (dialog);
+-}
+-
+-/*
+- * Display a dialog box with a list of options that can be turned on or off
+- * The `flag' parameter is used to select between radiolist and checklist.
+- */
+-int
+-dialog_checklist (const char *title, const char *prompt, int height, int width,
+-      int list_height, int item_no, struct dialog_list_item ** items,
+-      int flag)
+-
+-{
+-    int i, x, y, box_x, box_y;
+-    int key = 0, button = 0, choice = 0, scroll = 0, max_choice, *status;
+-    WINDOW *dialog, *list;
+-
+-    checkflag = flag;
+-
+-    /* Allocate space for storing item on/off status */
+-    if ((status = malloc (sizeof (int) * item_no)) == NULL) {
+-      endwin ();
+-      fprintf (stderr,
+-               "\nCan't allocate memory in dialog_checklist().\n");
+-      exit (-1);
+-    }
+-
+-    /* Initializes status */
+-    for (i = 0; i < item_no; i++) {
+-      status[i] = (items[i]->selected == 1); /* ON */
+-      if ((!choice && status[i]) || items[i]->selected == 2) /* SELECTED */
+-            choice = i + 1;
+-    }
+-    if (choice)
+-          choice--;
+-
+-    max_choice = MIN (list_height, item_no);
+-
+-    /* center dialog box on screen */
+-    x = (COLS - width) / 2;
+-    y = (LINES - height) / 2;
+-
+-    draw_shadow (stdscr, y, x, height, width);
+-
+-    dialog = newwin (height, width, y, x);
+-    keypad (dialog, TRUE);
+-
+-    draw_box (dialog, 0, 0, height, width, dialog_attr, border_attr);
+-    wattrset (dialog, border_attr);
+-    mvwaddch (dialog, height-3, 0, ACS_LTEE);
+-    for (i = 0; i < width - 2; i++)
+-      waddch (dialog, ACS_HLINE);
+-    wattrset (dialog, dialog_attr);
+-    waddch (dialog, ACS_RTEE);
+-
+-    if (title != NULL && strlen(title) >= width-2 ) {
+-      /* truncate long title -- mec */
+-      char * title2 = malloc(width-2+1);
+-      memcpy( title2, title, width-2 );
+-      title2[width-2] = '\0';
+-      title = title2;
+-    }
+-
+-    if (title != NULL) {
+-      wattrset (dialog, title_attr);
+-      mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' ');
+-      waddstr (dialog, (char *)title);
+-      waddch (dialog, ' ');
+-    }
+-
+-    wattrset (dialog, dialog_attr);
+-    print_autowrap (dialog, prompt, width - 2, 1, 3);
+-
+-    list_width = width - 6;
+-    box_y = height - list_height - 5;
+-    box_x = (width - list_width) / 2 - 1;
+-
+-    /* create new window for the list */
+-    list = subwin (dialog, list_height, list_width, y+box_y+1, x+box_x+1);
+-
+-    keypad (list, TRUE);
+-
+-    /* draw a box around the list items */
+-    draw_box (dialog, box_y, box_x, list_height + 2, list_width + 2,
+-            menubox_border_attr, menubox_attr);
+-
+-    /* Find length of longest item in order to center checklist */
+-    check_x = 0;
+-    for (i = 0; i < item_no; i++)
+-      check_x = MAX (check_x, + strlen (items[i]->name) + 4);
+-
+-    check_x = (list_width - check_x) / 2;
+-    item_x = check_x + 4;
+-
+-    if (choice >= list_height) {
+-      scroll = choice - list_height + 1;
+-      choice -= scroll;
+-    }
+-
+-    /* Print the list */
+-    for (i = 0; i < max_choice; i++) {
+-      print_item (list, items[scroll + i]->name,
+-                  status[i+scroll], i, i == choice);
+-    }
+-
+-    print_arrows(dialog, choice, item_no, scroll,
+-                      box_y, box_x + check_x + 5, list_height);
+-
+-    print_buttons(dialog, height, width, 0);
+-
+-    wnoutrefresh (list);
+-    wnoutrefresh (dialog);
+-    doupdate ();
+-
+-    while (key != ESC) {
+-      key = wgetch (dialog);
+-
+-      for (i = 0; i < max_choice; i++)
+-            if (toupper(key) == toupper(items[scroll + i]->name[0]))
+-                break;
+-
+-
+-      if ( i < max_choice || key == KEY_UP || key == KEY_DOWN ||
+-          key == '+' || key == '-' ) {
+-          if (key == KEY_UP || key == '-') {
+-              if (!choice) {
+-                  if (!scroll)
+-                      continue;
+-                  /* Scroll list down */
+-                  if (list_height > 1) {
+-                      /* De-highlight current first item */
+-                      print_item (list, items[scroll]->name,
+-                                      status[scroll], 0, FALSE);
+-                      scrollok (list, TRUE);
+-                      wscrl (list, -1);
+-                      scrollok (list, FALSE);
+-                  }
+-                  scroll--;
+-                  print_item (list, items[scroll]->name,
+-                              status[scroll], 0, TRUE);
+-                  wnoutrefresh (list);
+-
+-                  print_arrows(dialog, choice, item_no, scroll,
+-                              box_y, box_x + check_x + 5, list_height);
+-
+-                  wrefresh (dialog);
+-
+-                  continue;   /* wait for another key press */
+-              } else
+-                  i = choice - 1;
+-          } else if (key == KEY_DOWN || key == '+') {
+-              if (choice == max_choice - 1) {
+-                  if (scroll + choice >= item_no - 1)
+-                      continue;
+-                  /* Scroll list up */
+-                  if (list_height > 1) {
+-                      /* De-highlight current last item before scrolling up */
+-                      print_item (list, items[scroll + max_choice - 1]->name,
+-                                  status[scroll + max_choice - 1],
+-                                  max_choice - 1, FALSE);
+-                      scrollok (list, TRUE);
+-                      scroll (list);
+-                      scrollok (list, FALSE);
+-                  }
+-                  scroll++;
+-                  print_item (list, items[scroll + max_choice - 1]->name,
+-                              status[scroll + max_choice - 1],
+-                              max_choice - 1, TRUE);
+-                  wnoutrefresh (list);
+-
+-                  print_arrows(dialog, choice, item_no, scroll,
+-                              box_y, box_x + check_x + 5, list_height);
+-
+-                  wrefresh (dialog);
+-
+-                  continue;   /* wait for another key press */
+-              } else
+-                  i = choice + 1;
+-          }
+-          if (i != choice) {
+-              /* De-highlight current item */
+-              print_item (list, items[scroll + choice]->name,
+-                          status[scroll + choice], choice, FALSE);
+-              /* Highlight new item */
+-              choice = i;
+-              print_item (list, items[scroll + choice]->name,
+-                          status[scroll + choice], choice, TRUE);
+-              wnoutrefresh (list);
+-              wrefresh (dialog);
+-          }
+-          continue;           /* wait for another key press */
+-      }
+-      switch (key) {
+-      case 'H':
+-      case 'h':
+-      case '?':
+-          for (i = 0; i < item_no; i++)
+-              items[i]->selected = 0;
+-          items[scroll + choice]->selected = 1;
+-          delwin (dialog);
+-          free (status);
+-          return 1;
+-      case TAB:
+-      case KEY_LEFT:
+-      case KEY_RIGHT:
+-          button = ((key == KEY_LEFT ? --button : ++button) < 0)
+-                      ? 1 : (button > 1 ? 0 : button);
+-
+-          print_buttons(dialog, height, width, button);
+-          wrefresh (dialog);
+-          break;
+-      case 'S':
+-      case 's':
+-      case ' ':
+-      case '\n':
+-          if (!button) {
+-              if (flag == FLAG_CHECK) {
+-                  status[scroll + choice] = !status[scroll + choice];
+-                  wmove (list, choice, check_x);
+-                  wattrset (list, check_selected_attr);
+-                  wprintw (list, "[%c]", status[scroll + choice] ? 'X' : ' ');
+-              } else {
+-                  if (!status[scroll + choice]) {
+-                      for (i = 0; i < item_no; i++)
+-                          status[i] = 0;
+-                      status[scroll + choice] = 1;
+-                      for (i = 0; i < max_choice; i++)
+-                          print_item (list, items[scroll + i]->name,
+-                                      status[scroll + i], i, i == choice);
+-                  }
+-              }
+-              wnoutrefresh (list);
+-              wrefresh (dialog);
+-
+-              for (i = 0; i < item_no; i++) {
+-                      items[i]->selected = status[i];
+-              }
+-            } else {
+-                  for (i = 0; i < item_no; i++)
+-                          items[i]->selected = 0;
+-                  items[scroll + choice]->selected = 1;
+-          }
+-          delwin (dialog);
+-          free (status);
+-          return button;
+-      case 'X':
+-      case 'x':
+-          key = ESC;
+-      case ESC:
+-          break;
+-      }
+-
+-      /* Now, update everything... */
+-      doupdate ();
+-    }
+-
+-
+-    delwin (dialog);
+-    free (status);
+-    return -1;                        /* ESC pressed */
+-}
+diff -Nur busybox-1.00/scripts/config/colors.h busybox/scripts/config/colors.h
+--- busybox-1.00/scripts/config/colors.h       2002-12-05 09:41:06.000000000 +0100
++++ busybox/scripts/config/colors.h    1970-01-01 01:00:00.000000000 +0100
+@@ -1,161 +0,0 @@
+-/*
+- *  colors.h -- color attribute definitions
+- *
+- *  AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+- *
+- *  This program is free software; you can redistribute it and/or
+- *  modify it under the terms of the GNU General Public License
+- *  as published by the Free Software Foundation; either version 2
+- *  of the License, or (at your option) any later version.
+- *
+- *  This program is distributed in the hope that it will be useful,
+- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- *  GNU General Public License for more details.
+- *
+- *  You should have received a copy of the GNU General Public License
+- *  along with this program; if not, write to the Free Software
+- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+- */
+-
+-
+-/*
+- *   Default color definitions
+- *
+- *   *_FG = foreground
+- *   *_BG = background
+- *   *_HL = highlight?
+- */
+-#define SCREEN_FG                    COLOR_CYAN
+-#define SCREEN_BG                    COLOR_BLUE
+-#define SCREEN_HL                    TRUE
+-
+-#define SHADOW_FG                    COLOR_BLACK
+-#define SHADOW_BG                    COLOR_BLACK
+-#define SHADOW_HL                    TRUE
+-
+-#define DIALOG_FG                    COLOR_BLACK
+-#define DIALOG_BG                    COLOR_WHITE
+-#define DIALOG_HL                    FALSE
+-
+-#define TITLE_FG                     COLOR_YELLOW
+-#define TITLE_BG                     COLOR_WHITE
+-#define TITLE_HL                     TRUE
+-
+-#define BORDER_FG                    COLOR_WHITE
+-#define BORDER_BG                    COLOR_WHITE
+-#define BORDER_HL                    TRUE
+-
+-#define BUTTON_ACTIVE_FG             COLOR_WHITE
+-#define BUTTON_ACTIVE_BG             COLOR_BLUE
+-#define BUTTON_ACTIVE_HL             TRUE
+-
+-#define BUTTON_INACTIVE_FG           COLOR_BLACK
+-#define BUTTON_INACTIVE_BG           COLOR_WHITE
+-#define BUTTON_INACTIVE_HL           FALSE
+-
+-#define BUTTON_KEY_ACTIVE_FG         COLOR_WHITE
+-#define BUTTON_KEY_ACTIVE_BG         COLOR_BLUE
+-#define BUTTON_KEY_ACTIVE_HL         TRUE
+-
+-#define BUTTON_KEY_INACTIVE_FG       COLOR_RED
+-#define BUTTON_KEY_INACTIVE_BG       COLOR_WHITE
+-#define BUTTON_KEY_INACTIVE_HL       FALSE
+-
+-#define BUTTON_LABEL_ACTIVE_FG       COLOR_YELLOW
+-#define BUTTON_LABEL_ACTIVE_BG       COLOR_BLUE
+-#define BUTTON_LABEL_ACTIVE_HL       TRUE
+-
+-#define BUTTON_LABEL_INACTIVE_FG     COLOR_BLACK
+-#define BUTTON_LABEL_INACTIVE_BG     COLOR_WHITE
+-#define BUTTON_LABEL_INACTIVE_HL     TRUE
+-
+-#define INPUTBOX_FG                  COLOR_BLACK
+-#define INPUTBOX_BG                  COLOR_WHITE
+-#define INPUTBOX_HL                  FALSE
+-
+-#define INPUTBOX_BORDER_FG           COLOR_BLACK
+-#define INPUTBOX_BORDER_BG           COLOR_WHITE
+-#define INPUTBOX_BORDER_HL           FALSE
+-
+-#define SEARCHBOX_FG                 COLOR_BLACK
+-#define SEARCHBOX_BG                 COLOR_WHITE
+-#define SEARCHBOX_HL                 FALSE
+-
+-#define SEARCHBOX_TITLE_FG           COLOR_YELLOW
+-#define SEARCHBOX_TITLE_BG           COLOR_WHITE
+-#define SEARCHBOX_TITLE_HL           TRUE
+-
+-#define SEARCHBOX_BORDER_FG          COLOR_WHITE
+-#define SEARCHBOX_BORDER_BG          COLOR_WHITE
+-#define SEARCHBOX_BORDER_HL          TRUE
+-
+-#define POSITION_INDICATOR_FG        COLOR_YELLOW
+-#define POSITION_INDICATOR_BG        COLOR_WHITE
+-#define POSITION_INDICATOR_HL        TRUE
+-
+-#define MENUBOX_FG                   COLOR_BLACK
+-#define MENUBOX_BG                   COLOR_WHITE
+-#define MENUBOX_HL                   FALSE
+-
+-#define MENUBOX_BORDER_FG            COLOR_WHITE
+-#define MENUBOX_BORDER_BG            COLOR_WHITE
+-#define MENUBOX_BORDER_HL            TRUE
+-
+-#define ITEM_FG                      COLOR_BLACK
+-#define ITEM_BG                      COLOR_WHITE
+-#define ITEM_HL                      FALSE
+-
+-#define ITEM_SELECTED_FG             COLOR_WHITE
+-#define ITEM_SELECTED_BG             COLOR_BLUE
+-#define ITEM_SELECTED_HL             TRUE
+-
+-#define TAG_FG                       COLOR_YELLOW
+-#define TAG_BG                       COLOR_WHITE
+-#define TAG_HL                       TRUE
+-
+-#define TAG_SELECTED_FG              COLOR_YELLOW
+-#define TAG_SELECTED_BG              COLOR_BLUE
+-#define TAG_SELECTED_HL              TRUE
+-
+-#define TAG_KEY_FG                   COLOR_YELLOW
+-#define TAG_KEY_BG                   COLOR_WHITE
+-#define TAG_KEY_HL                   TRUE
+-
+-#define TAG_KEY_SELECTED_FG          COLOR_YELLOW
+-#define TAG_KEY_SELECTED_BG          COLOR_BLUE
+-#define TAG_KEY_SELECTED_HL          TRUE
+-
+-#define CHECK_FG                     COLOR_BLACK
+-#define CHECK_BG                     COLOR_WHITE
+-#define CHECK_HL                     FALSE
+-
+-#define CHECK_SELECTED_FG            COLOR_WHITE
+-#define CHECK_SELECTED_BG            COLOR_BLUE
+-#define CHECK_SELECTED_HL            TRUE
+-
+-#define UARROW_FG                    COLOR_GREEN
+-#define UARROW_BG                    COLOR_WHITE
+-#define UARROW_HL                    TRUE
+-
+-#define DARROW_FG                    COLOR_GREEN
+-#define DARROW_BG                    COLOR_WHITE
+-#define DARROW_HL                    TRUE
+-
+-/* End of default color definitions */
+-
+-#define C_ATTR(x,y)                  ((x ? A_BOLD : 0) | COLOR_PAIR((y)))
+-#define COLOR_NAME_LEN               10
+-#define COLOR_COUNT                  8
+-
+-/*
+- * Global variables
+- */
+-
+-typedef struct {
+-    char name[COLOR_NAME_LEN];
+-    int value;
+-} color_names_st;
+-
+-extern color_names_st color_names[];
+-extern int color_table[][3];
+diff -Nur busybox-1.00/scripts/config/conf.c busybox/scripts/config/conf.c
+--- busybox-1.00/scripts/config/conf.c 2004-01-16 13:48:53.000000000 +0100
++++ busybox/scripts/config/conf.c      2005-06-04 08:20:03.000000000 +0200
+@@ -31,14 +31,14 @@
+ static int indent = 1;
+ static int valid_stdin = 1;
+ static int conf_cnt;
+-static char line[128];
++static signed char line[128];
+ static struct menu *rootEntry;
+ static char nohelp_text[] = "Sorry, no help available for this option yet.\n";
+-static void strip(char *str)
++static void strip(signed char *str)
+ {
+-      char *p = str;
++      signed char *p = str;
+       int l;
+       while ((isspace(*p)))
+diff -Nur busybox-1.00/scripts/config/confdata.c busybox/scripts/config/confdata.c
+--- busybox-1.00/scripts/config/confdata.c     2004-07-15 08:01:05.000000000 +0200
++++ busybox/scripts/config/confdata.c  2005-06-04 08:20:03.000000000 +0200
+@@ -23,10 +23,10 @@
+       NULL,
+ };
+-static char *conf_expand_value(const char *in)
++static char *conf_expand_value(const signed char *in)
+ {
+       struct symbol *sym;
+-      const char *src;
++      const signed char *src;
+       static char res_value[SYMBOL_MAXLENGTH];
+       char *dst, name[SYMBOL_MAXLENGTH];
+@@ -287,7 +287,7 @@
+       } else
+               basename = conf_def_filename;
+-      sprintf(newname, "%s.tmpconfig.%d", dirname, getpid());
++      sprintf(newname, "%s.tmpconfig.%d", dirname, (int)getpid());
+       out = fopen(newname, "w");
+       if (!out)
+               return 1;
+diff -Nur busybox-1.00/scripts/config/dialog.h busybox/scripts/config/dialog.h
+--- busybox-1.00/scripts/config/dialog.h       2004-03-15 09:29:08.000000000 +0100
++++ busybox/scripts/config/dialog.h    1970-01-01 01:00:00.000000000 +0100
+@@ -1,196 +0,0 @@
+-
+-/*
+- *  dialog.h -- common declarations for all dialog modules
+- *
+- *  AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+- *
+- *  This program is free software; you can redistribute it and/or
+- *  modify it under the terms of the GNU General Public License
+- *  as published by the Free Software Foundation; either version 2
+- *  of the License, or (at your option) any later version.
+- *
+- *  This program is distributed in the hope that it will be useful,
+- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- *  GNU General Public License for more details.
+- *
+- *  You should have received a copy of the GNU General Public License
+- *  along with this program; if not, write to the Free Software
+- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+- */
+-
+-#include <sys/types.h>
+-#include <fcntl.h>
+-#include <unistd.h>
+-#include <ctype.h>
+-#include <stdlib.h>
+-#include <string.h>
+-
+-#ifdef CURSES_LOC
+-#include CURSES_LOC
+-
+-/*
+- * Colors in ncurses 1.9.9e do not work properly since foreground and
+- * background colors are OR'd rather than separately masked.  This version
+- * of dialog was hacked to work with ncurses 1.9.9e, making it incompatible
+- * with standard curses.  The simplest fix (to make this work with standard
+- * curses) uses the wbkgdset() function, not used in the original hack.
+- * Turn it off if we're building with 1.9.9e, since it just confuses things.
+- */
+-#if defined(NCURSES_VERSION) && defined(_NEED_WRAP) && !defined(GCC_PRINTFLIKE)
+-#define OLD_NCURSES 1
+-#undef  wbkgdset
+-#define wbkgdset(w,p) /*nothing*/
+-#else
+-#define OLD_NCURSES 0
+-#endif
+-
+-#define TR(params) _tracef params
+-
+-#define ESC 27
+-#define TAB 9
+-#define MAX_LEN 2048
+-#define BUF_SIZE (10*1024)
+-#define MIN(x,y) (x < y ? x : y)
+-#define MAX(x,y) (x > y ? x : y)
+-
+-
+-#ifndef ACS_ULCORNER
+-#define ACS_ULCORNER '+'
+-#endif
+-#ifndef ACS_LLCORNER
+-#define ACS_LLCORNER '+'
+-#endif
+-#ifndef ACS_URCORNER
+-#define ACS_URCORNER '+'
+-#endif
+-#ifndef ACS_LRCORNER
+-#define ACS_LRCORNER '+'
+-#endif
+-#ifndef ACS_HLINE
+-#define ACS_HLINE '-'
+-#endif
+-#ifndef ACS_VLINE
+-#define ACS_VLINE '|'
+-#endif
+-#ifndef ACS_LTEE
+-#define ACS_LTEE '+'
+-#endif
+-#ifndef ACS_RTEE
+-#define ACS_RTEE '+'
+-#endif
+-#ifndef ACS_UARROW
+-#define ACS_UARROW '^'
+-#endif
+-#ifndef ACS_DARROW
+-#define ACS_DARROW 'v'
+-#endif
+-
+-/*
+- * Attribute names
+- */
+-#define screen_attr                   attributes[0]
+-#define shadow_attr                   attributes[1]
+-#define dialog_attr                   attributes[2]
+-#define title_attr                    attributes[3]
+-#define border_attr                   attributes[4]
+-#define button_active_attr            attributes[5]
+-#define button_inactive_attr          attributes[6]
+-#define button_key_active_attr        attributes[7]
+-#define button_key_inactive_attr      attributes[8]
+-#define button_label_active_attr      attributes[9]
+-#define button_label_inactive_attr    attributes[10]
+-#define inputbox_attr                 attributes[11]
+-#define inputbox_border_attr          attributes[12]
+-#define searchbox_attr                attributes[13]
+-#define searchbox_title_attr          attributes[14]
+-#define searchbox_border_attr         attributes[15]
+-#define position_indicator_attr       attributes[16]
+-#define menubox_attr                  attributes[17]
+-#define menubox_border_attr           attributes[18]
+-#define item_attr                     attributes[19]
+-#define item_selected_attr            attributes[20]
+-#define tag_attr                      attributes[21]
+-#define tag_selected_attr             attributes[22]
+-#define tag_key_attr                  attributes[23]
+-#define tag_key_selected_attr         attributes[24]
+-#define check_attr                    attributes[25]
+-#define check_selected_attr           attributes[26]
+-#define uarrow_attr                   attributes[27]
+-#define darrow_attr                   attributes[28]
+-
+-/* number of attributes */
+-#define ATTRIBUTE_COUNT               29
+-
+-/*
+- * Global variables
+- */
+-extern bool use_colors;
+-
+-extern chtype attributes[];
+-#endif
+-
+-extern char *backtitle;
+-
+-struct dialog_list_item {
+-      char *name;
+-      int namelen;
+-      char *tag;
+-      int selected; /* Set to 1 by dialog_*() function. */
+-};
+-
+-/*
+- * Function prototypes
+- */
+-
+-void init_dialog (void);
+-void end_dialog (void);
+-void dialog_clear (void);
+-#ifdef CURSES_LOC
+-void attr_clear (WINDOW * win, int height, int width, chtype attr);
+-void color_setup (void);
+-void print_autowrap (WINDOW * win, const char *prompt, int width, int y, int x);
+-void print_button (WINDOW * win, const char *label, int y, int x, int selected);
+-void draw_box (WINDOW * win, int y, int x, int height, int width, chtype box,
+-              chtype border);
+-void draw_shadow (WINDOW * win, int y, int x, int height, int width);
+-#endif
+-
+-int first_alpha (const char *string, const char *exempt);
+-int dialog_yesno (const char *title, const char *prompt, int height, int width);
+-int dialog_msgbox (const char *title, const char *prompt, int height,
+-              int width, int pause);
+-int dialog_textbox (const char *title, const char *file, int height, int width);
+-int dialog_menu (const char *title, const char *prompt, int height, int width,
+-              int menu_height, const char *choice, int item_no,
+-              struct dialog_list_item ** items);
+-int dialog_checklist (const char *title, const char *prompt, int height,
+-              int width, int list_height, int item_no,
+-              struct dialog_list_item ** items, int flag);
+-extern unsigned char dialog_input_result[];
+-int dialog_inputbox (const char *title, const char *prompt, int height,
+-              int width, const char *init);
+-
+-struct dialog_list_item *first_sel_item(int item_no,
+-              struct dialog_list_item ** items);
+-
+-/*
+- * This is the base for fictitious keys, which activate
+- * the buttons.
+- *
+- * Mouse-generated keys are the following:
+- *   -- the first 32 are used as numbers, in addition to '0'-'9'
+- *   -- the lowercase are used to signal mouse-enter events (M_EVENT + 'o')
+- *   -- uppercase chars are used to invoke the button (M_EVENT + 'O')
+- */
+-#ifdef CURSES_LOC
+-#define M_EVENT (KEY_MAX+1)
+-#endif
+-
+-
+-/*
+- * The `flag' parameter in checklist is used to select between
+- * radiolist and checklist
+- */
+-#define FLAG_CHECK 1
+-#define FLAG_RADIO 0
+diff -Nur busybox-1.00/scripts/config/expr.c busybox/scripts/config/expr.c
+--- busybox-1.00/scripts/config/expr.c 2004-07-15 08:01:05.000000000 +0200
++++ busybox/scripts/config/expr.c      2005-06-04 08:20:03.000000000 +0200
+@@ -1087,3 +1087,13 @@
+ {
+       expr_print(e, expr_print_file_helper, out, E_NONE);
+ }
++
++static void expr_print_gstr_helper(void *data, const char *str)
++{
++      str_append((struct gstr*)data, str);
++}
++
++void expr_gstr_print(struct expr *e, struct gstr *gs)
++{
++      expr_print(e, expr_print_gstr_helper, gs, E_NONE);
++}
+diff -Nur busybox-1.00/scripts/config/expr.h busybox/scripts/config/expr.h
+--- busybox-1.00/scripts/config/expr.h 2004-07-15 08:01:05.000000000 +0200
++++ busybox/scripts/config/expr.h      2005-06-04 08:20:03.000000000 +0200
+@@ -174,6 +174,8 @@
+ struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym);
+ void expr_fprint(struct expr *e, FILE *out);
++struct gstr; /* forward */
++void expr_gstr_print(struct expr *e, struct gstr *gs);
+ static inline int expr_is_yes(struct expr *e)
+ {
+diff -Nur busybox-1.00/scripts/config/inputbox.c busybox/scripts/config/inputbox.c
+--- busybox-1.00/scripts/config/inputbox.c     2002-12-05 09:41:07.000000000 +0100
++++ busybox/scripts/config/inputbox.c  1970-01-01 01:00:00.000000000 +0100
+@@ -1,240 +0,0 @@
+-/*
+- *  inputbox.c -- implements the input box
+- *
+- *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+- *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+- *
+- *  This program is free software; you can redistribute it and/or
+- *  modify it under the terms of the GNU General Public License
+- *  as published by the Free Software Foundation; either version 2
+- *  of the License, or (at your option) any later version.
+- *
+- *  This program is distributed in the hope that it will be useful,
+- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- *  GNU General Public License for more details.
+- *
+- *  You should have received a copy of the GNU General Public License
+- *  along with this program; if not, write to the Free Software
+- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+- */
+-
+-#include "dialog.h"
+-
+-unsigned char dialog_input_result[MAX_LEN + 1];
+-
+-/*
+- *  Print the termination buttons
+- */
+-static void
+-print_buttons(WINDOW *dialog, int height, int width, int selected)
+-{
+-    int x = width / 2 - 11;
+-    int y = height - 2;
+-
+-    print_button (dialog, "  Ok  ", y, x, selected==0);
+-    print_button (dialog, " Help ", y, x + 14, selected==1);
+-
+-    wmove(dialog, y, x+1+14*selected);
+-    wrefresh(dialog);
+-}
+-
+-/*
+- * Display a dialog box for inputing a string
+- */
+-int
+-dialog_inputbox (const char *title, const char *prompt, int height, int width,
+-               const char *init)
+-{
+-    int i, x, y, box_y, box_x, box_width;
+-    int input_x = 0, scroll = 0, key = 0, button = -1;
+-    unsigned char *instr = dialog_input_result;
+-    WINDOW *dialog;
+-
+-    /* center dialog box on screen */
+-    x = (COLS - width) / 2;
+-    y = (LINES - height) / 2;
+-
+-
+-    draw_shadow (stdscr, y, x, height, width);
+-
+-    dialog = newwin (height, width, y, x);
+-    keypad (dialog, TRUE);
+-
+-    draw_box (dialog, 0, 0, height, width, dialog_attr, border_attr);
+-    wattrset (dialog, border_attr);
+-    mvwaddch (dialog, height-3, 0, ACS_LTEE);
+-    for (i = 0; i < width - 2; i++)
+-      waddch (dialog, ACS_HLINE);
+-    wattrset (dialog, dialog_attr);
+-    waddch (dialog, ACS_RTEE);
+-
+-    if (title != NULL && strlen(title) >= width-2 ) {
+-      /* truncate long title -- mec */
+-      char * title2 = malloc(width-2+1);
+-      memcpy( title2, title, width-2 );
+-      title2[width-2] = '\0';
+-      title = title2;
+-    }
+-
+-    if (title != NULL) {
+-      wattrset (dialog, title_attr);
+-      mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' ');
+-      waddstr (dialog, (char *)title);
+-      waddch (dialog, ' ');
+-    }
+-
+-    wattrset (dialog, dialog_attr);
+-    print_autowrap (dialog, prompt, width - 2, 1, 3);
+-
+-    /* Draw the input field box */
+-    box_width = width - 6;
+-    getyx (dialog, y, x);
+-    box_y = y + 2;
+-    box_x = (width - box_width) / 2;
+-    draw_box (dialog, y + 1, box_x - 1, 3, box_width + 2,
+-            border_attr, dialog_attr);
+-
+-    print_buttons(dialog, height, width, 0);
+-
+-    /* Set up the initial value */
+-    wmove (dialog, box_y, box_x);
+-    wattrset (dialog, inputbox_attr);
+-
+-    if (!init)
+-      instr[0] = '\0';
+-    else
+-      strcpy (instr, init);
+-
+-    input_x = strlen (instr);
+-
+-    if (input_x >= box_width) {
+-      scroll = input_x - box_width + 1;
+-      input_x = box_width - 1;
+-      for (i = 0; i < box_width - 1; i++)
+-          waddch (dialog, instr[scroll + i]);
+-    } else
+-      waddstr (dialog, instr);
+-
+-    wmove (dialog, box_y, box_x + input_x);
+-
+-    wrefresh (dialog);
+-
+-    while (key != ESC) {
+-      key = wgetch (dialog);
+-
+-      if (button == -1) {     /* Input box selected */
+-          switch (key) {
+-          case TAB:
+-          case KEY_UP:
+-          case KEY_DOWN:
+-              break;
+-          case KEY_LEFT:
+-              continue;
+-          case KEY_RIGHT:
+-              continue;
+-          case KEY_BACKSPACE:
+-          case 127:
+-              if (input_x || scroll) {
+-                  wattrset (dialog, inputbox_attr);
+-                  if (!input_x) {
+-                      scroll = scroll < box_width - 1 ?
+-                          0 : scroll - (box_width - 1);
+-                      wmove (dialog, box_y, box_x);
+-                      for (i = 0; i < box_width; i++)
+-                          waddch (dialog, instr[scroll + input_x + i] ?
+-                                  instr[scroll + input_x + i] : ' ');
+-                      input_x = strlen (instr) - scroll;
+-                  } else
+-                      input_x--;
+-                  instr[scroll + input_x] = '\0';
+-                  mvwaddch (dialog, box_y, input_x + box_x, ' ');
+-                  wmove (dialog, box_y, input_x + box_x);
+-                  wrefresh (dialog);
+-              }
+-              continue;
+-          default:
+-              if (key < 0x100 && isprint (key)) {
+-                  if (scroll + input_x < MAX_LEN) {
+-                      wattrset (dialog, inputbox_attr);
+-                      instr[scroll + input_x] = key;
+-                      instr[scroll + input_x + 1] = '\0';
+-                      if (input_x == box_width - 1) {
+-                          scroll++;
+-                          wmove (dialog, box_y, box_x);
+-                          for (i = 0; i < box_width - 1; i++)
+-                              waddch (dialog, instr[scroll + i]);
+-                      } else {
+-                          wmove (dialog, box_y, input_x++ + box_x);
+-                          waddch (dialog, key);
+-                      }
+-                      wrefresh (dialog);
+-                  } else
+-                      flash ();       /* Alarm user about overflow */
+-                  continue;
+-              }
+-          }
+-      }
+-      switch (key) {
+-      case 'O':
+-      case 'o':
+-          delwin (dialog);
+-          return 0;
+-      case 'H':
+-      case 'h':
+-          delwin (dialog);
+-          return 1;
+-      case KEY_UP:
+-      case KEY_LEFT:
+-          switch (button) {
+-          case -1:
+-              button = 1;     /* Indicates "Cancel" button is selected */
+-              print_buttons(dialog, height, width, 1);
+-              break;
+-          case 0:
+-              button = -1;    /* Indicates input box is selected */
+-              print_buttons(dialog, height, width, 0);
+-              wmove (dialog, box_y, box_x + input_x);
+-              wrefresh (dialog);
+-              break;
+-          case 1:
+-              button = 0;     /* Indicates "OK" button is selected */
+-              print_buttons(dialog, height, width, 0);
+-              break;
+-          }
+-          break;
+-      case TAB:
+-      case KEY_DOWN:
+-      case KEY_RIGHT:
+-          switch (button) {
+-          case -1:
+-              button = 0;     /* Indicates "OK" button is selected */
+-              print_buttons(dialog, height, width, 0);
+-              break;
+-          case 0:
+-              button = 1;     /* Indicates "Cancel" button is selected */
+-              print_buttons(dialog, height, width, 1);
+-              break;
+-          case 1:
+-              button = -1;    /* Indicates input box is selected */
+-              print_buttons(dialog, height, width, 0);
+-              wmove (dialog, box_y, box_x + input_x);
+-              wrefresh (dialog);
+-              break;
+-          }
+-          break;
+-      case ' ':
+-      case '\n':
+-          delwin (dialog);
+-          return (button == -1 ? 0 : button);
+-      case 'X':
+-      case 'x':
+-          key = ESC;
+-      case ESC:
+-          break;
+-      }
+-    }
+-
+-    delwin (dialog);
+-    return -1;                        /* ESC pressed */
+-}
+diff -Nur busybox-1.00/scripts/config/lkc.h busybox/scripts/config/lkc.h
+--- busybox-1.00/scripts/config/lkc.h  2003-08-05 04:18:24.000000000 +0200
++++ busybox/scripts/config/lkc.h       2005-06-04 08:20:03.000000000 +0200
+@@ -56,11 +56,21 @@
+ void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep);
+ void menu_finalize(struct menu *parent);
+ void menu_set_type(int type);
++
++/* util.c */
+ struct file *file_lookup(const char *name);
+ int file_write_dep(const char *name);
+-extern struct menu *current_entry;
+-extern struct menu *current_menu;
++struct gstr {
++      size_t len;
++      char  *s;
++};
++struct gstr str_new(void);
++struct gstr str_assign(const char *s);
++void str_free(struct gstr *gs);
++void str_append(struct gstr *gs, const char *s);
++void str_printf(struct gstr *gs, const char *fmt, ...);
++const char *str_get(struct gstr *gs);
+ /* symbol.c */
+ void sym_init(void);
+diff -Nur busybox-1.00/scripts/config/lkc_proto.h busybox/scripts/config/lkc_proto.h
+--- busybox-1.00/scripts/config/lkc_proto.h    2003-08-05 04:18:25.000000000 +0200
++++ busybox/scripts/config/lkc_proto.h 2005-06-04 08:20:03.000000000 +0200
+@@ -18,6 +18,7 @@
+ P(sym_lookup,struct symbol *,(const char *name, int isconst));
+ P(sym_find,struct symbol *,(const char *name));
++P(sym_re_search,struct symbol **,(const char *pattern));
+ P(sym_type_name,const char *,(enum symbol_type type));
+ P(sym_calc_value,void,(struct symbol *sym));
+ P(sym_get_type,enum symbol_type,(struct symbol *sym));
+diff -Nur busybox-1.00/scripts/config/lxdialog/BIG.FAT.WARNING busybox/scripts/config/lxdialog/BIG.FAT.WARNING
+--- busybox-1.00/scripts/config/lxdialog/BIG.FAT.WARNING       1970-01-01 01:00:00.000000000 +0100
++++ busybox/scripts/config/lxdialog/BIG.FAT.WARNING    2005-06-04 08:20:02.000000000 +0200
+@@ -0,0 +1,4 @@
++This is NOT the official version of dialog.  This version has been
++significantly modified from the original.  It is for use by the Linux
++kernel configuration script.  Please do not bother Savio Lam with 
++questions about this program.
+diff -Nur busybox-1.00/scripts/config/lxdialog/checklist.c busybox/scripts/config/lxdialog/checklist.c
+--- busybox-1.00/scripts/config/lxdialog/checklist.c   1970-01-01 01:00:00.000000000 +0100
++++ busybox/scripts/config/lxdialog/checklist.c        2005-06-04 08:20:02.000000000 +0200
+@@ -0,0 +1,372 @@
++/*
++ *  checklist.c -- implements the checklist box
++ *
++ *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
++ *     Stuart Herbert - S.Herbert@sheffield.ac.uk: radiolist extension
++ *     Alessandro Rubini - rubini@ipvvis.unipv.it: merged the two
++ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
++ *
++ *  This program is free software; you can redistribute it and/or
++ *  modify it under the terms of the GNU General Public License
++ *  as published by the Free Software Foundation; either version 2
++ *  of the License, or (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include "dialog.h"
++
++static int list_width, check_x, item_x, checkflag;
++
++/*
++ * Print list item
++ */
++static void
++print_item (WINDOW * win, const char *item, int status,
++          int choice, int selected)
++{
++    int i;
++
++    /* Clear 'residue' of last item */
++    wattrset (win, menubox_attr);
++    wmove (win, choice, 0);
++    for (i = 0; i < list_width; i++)
++      waddch (win, ' ');
++
++    wmove (win, choice, check_x);
++    wattrset (win, selected ? check_selected_attr : check_attr);
++    if (checkflag == FLAG_CHECK)
++      wprintw (win, "[%c]", status ? 'X' : ' ');
++    else
++      wprintw (win, "(%c)", status ? 'X' : ' ');
++
++    wattrset (win, selected ? tag_selected_attr : tag_attr);
++    mvwaddch(win, choice, item_x, item[0]);
++    wattrset (win, selected ? item_selected_attr : item_attr);
++    waddstr (win, (char *)item+1);
++    if (selected) {
++      wmove (win, choice, check_x+1);
++      wrefresh (win);
++    }
++}
++
++/*
++ * Print the scroll indicators.
++ */
++static void
++print_arrows (WINDOW * win, int choice, int item_no, int scroll,
++              int y, int x, int height)
++{
++    wmove(win, y, x);
++
++    if (scroll > 0) {
++      wattrset (win, uarrow_attr);
++      waddch (win, ACS_UARROW);
++      waddstr (win, "(-)");
++    }
++    else {
++      wattrset (win, menubox_attr);
++      waddch (win, ACS_HLINE);
++      waddch (win, ACS_HLINE);
++      waddch (win, ACS_HLINE);
++      waddch (win, ACS_HLINE);
++    }
++
++   y = y + height + 1;
++   wmove(win, y, x);
++
++   if ((height < item_no) && (scroll + choice < item_no - 1)) {
++      wattrset (win, darrow_attr);
++      waddch (win, ACS_DARROW);
++      waddstr (win, "(+)");
++    }
++    else {
++      wattrset (win, menubox_border_attr);
++      waddch (win, ACS_HLINE);
++      waddch (win, ACS_HLINE);
++      waddch (win, ACS_HLINE);
++      waddch (win, ACS_HLINE);
++   }
++}
++
++/*
++ *  Display the termination buttons
++ */
++static void
++print_buttons( WINDOW *dialog, int height, int width, int selected)
++{
++    int x = width / 2 - 11;
++    int y = height - 2;
++
++    print_button (dialog, "Select", y, x, selected == 0);
++    print_button (dialog, " Help ", y, x + 14, selected == 1);
++
++    wmove(dialog, y, x+1 + 14*selected);
++    wrefresh (dialog);
++}
++
++/*
++ * Display a dialog box with a list of options that can be turned on or off
++ * The `flag' parameter is used to select between radiolist and checklist.
++ */
++int
++dialog_checklist (const char *title, const char *prompt, int height, int width,
++      int list_height, int item_no, struct dialog_list_item ** items,
++      int flag)
++      
++{
++    int i, x, y, box_x, box_y;
++    int key = 0, button = 0, choice = 0, scroll = 0, max_choice, *status;
++    WINDOW *dialog, *list;
++
++    checkflag = flag;
++
++    /* Allocate space for storing item on/off status */
++    if ((status = malloc (sizeof (int) * item_no)) == NULL) {
++      endwin ();
++      fprintf (stderr,
++               "\nCan't allocate memory in dialog_checklist().\n");
++      exit (-1);
++    }
++
++    /* Initializes status */
++    for (i = 0; i < item_no; i++) {
++      status[i] = (items[i]->selected == 1); /* ON */
++      if ((!choice && status[i]) || items[i]->selected == 2) /* SELECTED */
++            choice = i + 1;
++    }
++    if (choice)
++          choice--;
++
++    max_choice = MIN (list_height, item_no);
++
++    /* center dialog box on screen */
++    x = (COLS - width) / 2;
++    y = (LINES - height) / 2;
++
++    draw_shadow (stdscr, y, x, height, width);
++
++    dialog = newwin (height, width, y, x);
++    keypad (dialog, TRUE);
++
++    draw_box (dialog, 0, 0, height, width, dialog_attr, border_attr);
++    wattrset (dialog, border_attr);
++    mvwaddch (dialog, height-3, 0, ACS_LTEE);
++    for (i = 0; i < width - 2; i++)
++      waddch (dialog, ACS_HLINE);
++    wattrset (dialog, dialog_attr);
++    waddch (dialog, ACS_RTEE);
++
++    if (title != NULL && strlen(title) >= width-2 ) {
++      /* truncate long title -- mec */
++      char * title2 = malloc(width-2+1);
++      memcpy( title2, title, width-2 );
++      title2[width-2] = '\0';
++      title = title2;
++    }
++
++    if (title != NULL) {
++      wattrset (dialog, title_attr);
++      mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' ');
++      waddstr (dialog, (char *)title);
++      waddch (dialog, ' ');
++    }
++
++    wattrset (dialog, dialog_attr);
++    print_autowrap (dialog, prompt, width - 2, 1, 3);
++
++    list_width = width - 6;
++    box_y = height - list_height - 5;
++    box_x = (width - list_width) / 2 - 1;
++
++    /* create new window for the list */
++    list = subwin (dialog, list_height, list_width, y+box_y+1, x+box_x+1);
++
++    keypad (list, TRUE);
++
++    /* draw a box around the list items */
++    draw_box (dialog, box_y, box_x, list_height + 2, list_width + 2,
++            menubox_border_attr, menubox_attr);
++
++    /* Find length of longest item in order to center checklist */
++    check_x = 0;
++    for (i = 0; i < item_no; i++) 
++      check_x = MAX (check_x, + strlen (items[i]->name) + 4);
++
++    check_x = (list_width - check_x) / 2;
++    item_x = check_x + 4;
++
++    if (choice >= list_height) {
++      scroll = choice - list_height + 1;
++      choice -= scroll;
++    }
++
++    /* Print the list */
++    for (i = 0; i < max_choice; i++) {
++      print_item (list, items[scroll + i]->name,
++                  status[i+scroll], i, i == choice);
++    }
++
++    print_arrows(dialog, choice, item_no, scroll,
++                      box_y, box_x + check_x + 5, list_height);
++
++    print_buttons(dialog, height, width, 0);
++
++    wnoutrefresh (list);
++    wnoutrefresh (dialog);
++    doupdate ();
++
++    while (key != ESC) {
++      key = wgetch (dialog);
++
++      for (i = 0; i < max_choice; i++)
++            if (toupper(key) == toupper(items[scroll + i]->name[0]))
++                break;
++
++
++      if ( i < max_choice || key == KEY_UP || key == KEY_DOWN || 
++          key == '+' || key == '-' ) {
++          if (key == KEY_UP || key == '-') {
++              if (!choice) {
++                  if (!scroll)
++                      continue;
++                  /* Scroll list down */
++                  if (list_height > 1) {
++                      /* De-highlight current first item */
++                      print_item (list, items[scroll]->name,
++                                      status[scroll], 0, FALSE);
++                      scrollok (list, TRUE);
++                      wscrl (list, -1);
++                      scrollok (list, FALSE);
++                  }
++                  scroll--;
++                  print_item (list, items[scroll]->name,
++                              status[scroll], 0, TRUE);
++                  wnoutrefresh (list);
++
++                  print_arrows(dialog, choice, item_no, scroll,
++                              box_y, box_x + check_x + 5, list_height);
++
++                  wrefresh (dialog);
++
++                  continue;   /* wait for another key press */
++              } else
++                  i = choice - 1;
++          } else if (key == KEY_DOWN || key == '+') {
++              if (choice == max_choice - 1) {
++                  if (scroll + choice >= item_no - 1)
++                      continue;
++                  /* Scroll list up */
++                  if (list_height > 1) {
++                      /* De-highlight current last item before scrolling up */
++                      print_item (list, items[scroll + max_choice - 1]->name,
++                                  status[scroll + max_choice - 1],
++                                  max_choice - 1, FALSE);
++                      scrollok (list, TRUE);
++                      scroll (list);
++                      scrollok (list, FALSE);
++                  }
++                  scroll++;
++                  print_item (list, items[scroll + max_choice - 1]->name,
++                              status[scroll + max_choice - 1],
++                              max_choice - 1, TRUE);
++                  wnoutrefresh (list);
++
++                  print_arrows(dialog, choice, item_no, scroll,
++                              box_y, box_x + check_x + 5, list_height);
++
++                  wrefresh (dialog);
++
++                  continue;   /* wait for another key press */
++              } else
++                  i = choice + 1;
++          }
++          if (i != choice) {
++              /* De-highlight current item */
++              print_item (list, items[scroll + choice]->name,
++                          status[scroll + choice], choice, FALSE);
++              /* Highlight new item */
++              choice = i;
++              print_item (list, items[scroll + choice]->name,
++                          status[scroll + choice], choice, TRUE);
++              wnoutrefresh (list);
++              wrefresh (dialog);
++          }
++          continue;           /* wait for another key press */
++      }
++      switch (key) {
++      case 'H':
++      case 'h':
++      case '?':
++          for (i = 0; i < item_no; i++)
++              items[i]->selected = 0;
++          items[scroll + choice]->selected = 1;
++          delwin (dialog);
++          free (status);
++          return 1;
++      case TAB:
++      case KEY_LEFT:
++      case KEY_RIGHT:
++          button = ((key == KEY_LEFT ? --button : ++button) < 0)
++                      ? 1 : (button > 1 ? 0 : button);
++
++          print_buttons(dialog, height, width, button);
++          wrefresh (dialog);
++          break;
++      case 'S':
++      case 's':
++      case ' ':
++      case '\n':
++          if (!button) {
++              if (flag == FLAG_CHECK) {
++                  status[scroll + choice] = !status[scroll + choice];
++                  wmove (list, choice, check_x);
++                  wattrset (list, check_selected_attr);
++                  wprintw (list, "[%c]", status[scroll + choice] ? 'X' : ' ');
++              } else {
++                  if (!status[scroll + choice]) {
++                      for (i = 0; i < item_no; i++)
++                          status[i] = 0;
++                      status[scroll + choice] = 1;
++                      for (i = 0; i < max_choice; i++)
++                          print_item (list, items[scroll + i]->name,
++                                      status[scroll + i], i, i == choice);
++                  }
++              }
++              wnoutrefresh (list);
++              wrefresh (dialog);
++            
++              for (i = 0; i < item_no; i++) {
++                      items[i]->selected = status[i];
++              }
++            } else {
++                  for (i = 0; i < item_no; i++)
++                          items[i]->selected = 0;
++                  items[scroll + choice]->selected = 1;
++          }
++          delwin (dialog);
++          free (status);
++          return button;
++      case 'X':
++      case 'x':
++          key = ESC;
++      case ESC:
++          break;
++      }
++
++      /* Now, update everything... */
++      doupdate ();
++    }
++    
++
++    delwin (dialog);
++    free (status);
++    return -1;                        /* ESC pressed */
++}
+diff -Nur busybox-1.00/scripts/config/lxdialog/colors.h busybox/scripts/config/lxdialog/colors.h
+--- busybox-1.00/scripts/config/lxdialog/colors.h      1970-01-01 01:00:00.000000000 +0100
++++ busybox/scripts/config/lxdialog/colors.h   2005-06-04 08:20:02.000000000 +0200
+@@ -0,0 +1,161 @@
++/*
++ *  colors.h -- color attribute definitions
++ *
++ *  AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
++ *
++ *  This program is free software; you can redistribute it and/or
++ *  modify it under the terms of the GNU General Public License
++ *  as published by the Free Software Foundation; either version 2
++ *  of the License, or (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++
++/*
++ *   Default color definitions
++ *
++ *   *_FG = foreground
++ *   *_BG = background
++ *   *_HL = highlight?
++ */
++#define SCREEN_FG                    COLOR_CYAN
++#define SCREEN_BG                    COLOR_BLUE
++#define SCREEN_HL                    TRUE
++
++#define SHADOW_FG                    COLOR_BLACK
++#define SHADOW_BG                    COLOR_BLACK
++#define SHADOW_HL                    TRUE
++
++#define DIALOG_FG                    COLOR_BLACK
++#define DIALOG_BG                    COLOR_WHITE
++#define DIALOG_HL                    FALSE
++
++#define TITLE_FG                     COLOR_YELLOW
++#define TITLE_BG                     COLOR_WHITE
++#define TITLE_HL                     TRUE
++
++#define BORDER_FG                    COLOR_WHITE
++#define BORDER_BG                    COLOR_WHITE
++#define BORDER_HL                    TRUE
++
++#define BUTTON_ACTIVE_FG             COLOR_WHITE
++#define BUTTON_ACTIVE_BG             COLOR_BLUE
++#define BUTTON_ACTIVE_HL             TRUE
++
++#define BUTTON_INACTIVE_FG           COLOR_BLACK
++#define BUTTON_INACTIVE_BG           COLOR_WHITE
++#define BUTTON_INACTIVE_HL           FALSE
++
++#define BUTTON_KEY_ACTIVE_FG         COLOR_WHITE
++#define BUTTON_KEY_ACTIVE_BG         COLOR_BLUE
++#define BUTTON_KEY_ACTIVE_HL         TRUE
++
++#define BUTTON_KEY_INACTIVE_FG       COLOR_RED
++#define BUTTON_KEY_INACTIVE_BG       COLOR_WHITE
++#define BUTTON_KEY_INACTIVE_HL       FALSE
++
++#define BUTTON_LABEL_ACTIVE_FG       COLOR_YELLOW
++#define BUTTON_LABEL_ACTIVE_BG       COLOR_BLUE
++#define BUTTON_LABEL_ACTIVE_HL       TRUE
++
++#define BUTTON_LABEL_INACTIVE_FG     COLOR_BLACK
++#define BUTTON_LABEL_INACTIVE_BG     COLOR_WHITE
++#define BUTTON_LABEL_INACTIVE_HL     TRUE
++
++#define INPUTBOX_FG                  COLOR_BLACK
++#define INPUTBOX_BG                  COLOR_WHITE
++#define INPUTBOX_HL                  FALSE
++
++#define INPUTBOX_BORDER_FG           COLOR_BLACK
++#define INPUTBOX_BORDER_BG           COLOR_WHITE
++#define INPUTBOX_BORDER_HL           FALSE
++
++#define SEARCHBOX_FG                 COLOR_BLACK
++#define SEARCHBOX_BG                 COLOR_WHITE
++#define SEARCHBOX_HL                 FALSE
++
++#define SEARCHBOX_TITLE_FG           COLOR_YELLOW
++#define SEARCHBOX_TITLE_BG           COLOR_WHITE
++#define SEARCHBOX_TITLE_HL           TRUE
++
++#define SEARCHBOX_BORDER_FG          COLOR_WHITE
++#define SEARCHBOX_BORDER_BG          COLOR_WHITE
++#define SEARCHBOX_BORDER_HL          TRUE
++
++#define POSITION_INDICATOR_FG        COLOR_YELLOW
++#define POSITION_INDICATOR_BG        COLOR_WHITE
++#define POSITION_INDICATOR_HL        TRUE
++
++#define MENUBOX_FG                   COLOR_BLACK
++#define MENUBOX_BG                   COLOR_WHITE
++#define MENUBOX_HL                   FALSE
++
++#define MENUBOX_BORDER_FG            COLOR_WHITE
++#define MENUBOX_BORDER_BG            COLOR_WHITE
++#define MENUBOX_BORDER_HL            TRUE
++
++#define ITEM_FG                      COLOR_BLACK
++#define ITEM_BG                      COLOR_WHITE
++#define ITEM_HL                      FALSE
++
++#define ITEM_SELECTED_FG             COLOR_WHITE
++#define ITEM_SELECTED_BG             COLOR_BLUE
++#define ITEM_SELECTED_HL             TRUE
++
++#define TAG_FG                       COLOR_YELLOW
++#define TAG_BG                       COLOR_WHITE
++#define TAG_HL                       TRUE
++
++#define TAG_SELECTED_FG              COLOR_YELLOW
++#define TAG_SELECTED_BG              COLOR_BLUE
++#define TAG_SELECTED_HL              TRUE
++
++#define TAG_KEY_FG                   COLOR_YELLOW
++#define TAG_KEY_BG                   COLOR_WHITE
++#define TAG_KEY_HL                   TRUE
++
++#define TAG_KEY_SELECTED_FG          COLOR_YELLOW
++#define TAG_KEY_SELECTED_BG          COLOR_BLUE
++#define TAG_KEY_SELECTED_HL          TRUE
++
++#define CHECK_FG                     COLOR_BLACK
++#define CHECK_BG                     COLOR_WHITE
++#define CHECK_HL                     FALSE
++
++#define CHECK_SELECTED_FG            COLOR_WHITE
++#define CHECK_SELECTED_BG            COLOR_BLUE
++#define CHECK_SELECTED_HL            TRUE
++
++#define UARROW_FG                    COLOR_GREEN
++#define UARROW_BG                    COLOR_WHITE
++#define UARROW_HL                    TRUE
++
++#define DARROW_FG                    COLOR_GREEN
++#define DARROW_BG                    COLOR_WHITE
++#define DARROW_HL                    TRUE
++
++/* End of default color definitions */
++
++#define C_ATTR(x,y)                  ((x ? A_BOLD : 0) | COLOR_PAIR((y)))
++#define COLOR_NAME_LEN               10
++#define COLOR_COUNT                  8
++
++/*
++ * Global variables
++ */
++
++typedef struct {
++    char name[COLOR_NAME_LEN];
++    int value;
++} color_names_st;
++
++extern color_names_st color_names[];
++extern int color_table[][3];
+diff -Nur busybox-1.00/scripts/config/lxdialog/dialog.h busybox/scripts/config/lxdialog/dialog.h
+--- busybox-1.00/scripts/config/lxdialog/dialog.h      1970-01-01 01:00:00.000000000 +0100
++++ busybox/scripts/config/lxdialog/dialog.h   2005-06-04 08:20:02.000000000 +0200
+@@ -0,0 +1,199 @@
++
++/*
++ *  dialog.h -- common declarations for all dialog modules
++ *
++ *  AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
++ *
++ *  This program is free software; you can redistribute it and/or
++ *  modify it under the terms of the GNU General Public License
++ *  as published by the Free Software Foundation; either version 2
++ *  of the License, or (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include <sys/types.h>
++#include <fcntl.h>
++#include <unistd.h>
++#include <ctype.h>
++#include <stdlib.h>
++#include <string.h>
++
++#ifdef CURSES_LOC
++#ifdef __sun__
++#define CURS_MACROS
++#endif
++#include CURSES_LOC
++
++/*
++ * Colors in ncurses 1.9.9e do not work properly since foreground and
++ * background colors are OR'd rather than separately masked.  This version
++ * of dialog was hacked to work with ncurses 1.9.9e, making it incompatible
++ * with standard curses.  The simplest fix (to make this work with standard
++ * curses) uses the wbkgdset() function, not used in the original hack.
++ * Turn it off if we're building with 1.9.9e, since it just confuses things.
++ */
++#if defined(NCURSES_VERSION) && defined(_NEED_WRAP) && !defined(GCC_PRINTFLIKE)
++#define OLD_NCURSES 1
++#undef  wbkgdset
++#define wbkgdset(w,p) /*nothing*/
++#else
++#define OLD_NCURSES 0
++#endif
++
++#define TR(params) _tracef params
++
++#define ESC 27
++#define TAB 9
++#define MAX_LEN 2048
++#define BUF_SIZE (10*1024)
++#define MIN(x,y) (x < y ? x : y)
++#define MAX(x,y) (x > y ? x : y)
++
++
++#ifndef ACS_ULCORNER
++#define ACS_ULCORNER '+'
++#endif
++#ifndef ACS_LLCORNER
++#define ACS_LLCORNER '+'
++#endif
++#ifndef ACS_URCORNER
++#define ACS_URCORNER '+'
++#endif
++#ifndef ACS_LRCORNER
++#define ACS_LRCORNER '+'
++#endif
++#ifndef ACS_HLINE
++#define ACS_HLINE '-'
++#endif
++#ifndef ACS_VLINE
++#define ACS_VLINE '|'
++#endif
++#ifndef ACS_LTEE
++#define ACS_LTEE '+'
++#endif
++#ifndef ACS_RTEE
++#define ACS_RTEE '+'
++#endif
++#ifndef ACS_UARROW
++#define ACS_UARROW '^'
++#endif
++#ifndef ACS_DARROW
++#define ACS_DARROW 'v'
++#endif
++
++/* 
++ * Attribute names
++ */
++#define screen_attr                   attributes[0]
++#define shadow_attr                   attributes[1]
++#define dialog_attr                   attributes[2]
++#define title_attr                    attributes[3]
++#define border_attr                   attributes[4]
++#define button_active_attr            attributes[5]
++#define button_inactive_attr          attributes[6]
++#define button_key_active_attr        attributes[7]
++#define button_key_inactive_attr      attributes[8]
++#define button_label_active_attr      attributes[9]
++#define button_label_inactive_attr    attributes[10]
++#define inputbox_attr                 attributes[11]
++#define inputbox_border_attr          attributes[12]
++#define searchbox_attr                attributes[13]
++#define searchbox_title_attr          attributes[14]
++#define searchbox_border_attr         attributes[15]
++#define position_indicator_attr       attributes[16]
++#define menubox_attr                  attributes[17]
++#define menubox_border_attr           attributes[18]
++#define item_attr                     attributes[19]
++#define item_selected_attr            attributes[20]
++#define tag_attr                      attributes[21]
++#define tag_selected_attr             attributes[22]
++#define tag_key_attr                  attributes[23]
++#define tag_key_selected_attr         attributes[24]
++#define check_attr                    attributes[25]
++#define check_selected_attr           attributes[26]
++#define uarrow_attr                   attributes[27]
++#define darrow_attr                   attributes[28]
++
++/* number of attributes */
++#define ATTRIBUTE_COUNT               29
++
++/*
++ * Global variables
++ */
++extern bool use_colors;
++
++extern chtype attributes[];
++#endif
++
++extern const char *backtitle;
++
++struct dialog_list_item {
++      char *name;
++      int namelen;
++      char *tag;
++      int selected; /* Set to 1 by dialog_*() function. */
++};
++
++/*
++ * Function prototypes
++ */
++
++void init_dialog (void);
++void end_dialog (void);
++void dialog_clear (void);
++#ifdef CURSES_LOC
++void attr_clear (WINDOW * win, int height, int width, chtype attr);
++void color_setup (void);
++void print_autowrap (WINDOW * win, const char *prompt, int width, int y, int x);
++void print_button (WINDOW * win, const char *label, int y, int x, int selected);
++void draw_box (WINDOW * win, int y, int x, int height, int width, chtype box,
++              chtype border);
++void draw_shadow (WINDOW * win, int y, int x, int height, int width);
++#endif
++
++int first_alpha (const char *string, const char *exempt);
++int dialog_yesno (const char *title, const char *prompt, int height, int width);
++int dialog_msgbox (const char *title, const char *prompt, int height,
++              int width, int pause);
++int dialog_textbox (const char *title, const char *file, int height, int width);
++int dialog_menu (const char *title, const char *prompt, int height, int width,
++              int menu_height, const char *choice, int item_no, 
++              struct dialog_list_item ** items);
++int dialog_checklist (const char *title, const char *prompt, int height,
++              int width, int list_height, int item_no,
++              struct dialog_list_item ** items, int flag);
++extern unsigned char dialog_input_result[];
++int dialog_inputbox (const char *title, const char *prompt, int height,
++              int width, const char *init);
++
++struct dialog_list_item *first_sel_item(int item_no,
++              struct dialog_list_item ** items);
++
++/*
++ * This is the base for fictitious keys, which activate
++ * the buttons.
++ *
++ * Mouse-generated keys are the following:
++ *   -- the first 32 are used as numbers, in addition to '0'-'9'
++ *   -- the lowercase are used to signal mouse-enter events (M_EVENT + 'o')
++ *   -- uppercase chars are used to invoke the button (M_EVENT + 'O')
++ */
++#ifdef CURSES_LOC
++#define M_EVENT (KEY_MAX+1)
++#endif
++
++
++/*
++ * The `flag' parameter in checklist is used to select between
++ * radiolist and checklist
++ */
++#define FLAG_CHECK 1
++#define FLAG_RADIO 0
+diff -Nur busybox-1.00/scripts/config/lxdialog/inputbox.c busybox/scripts/config/lxdialog/inputbox.c
+--- busybox-1.00/scripts/config/lxdialog/inputbox.c    1970-01-01 01:00:00.000000000 +0100
++++ busybox/scripts/config/lxdialog/inputbox.c 2005-06-04 08:20:02.000000000 +0200
+@@ -0,0 +1,240 @@
++/*
++ *  inputbox.c -- implements the input box
++ *
++ *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
++ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
++ *
++ *  This program is free software; you can redistribute it and/or
++ *  modify it under the terms of the GNU General Public License
++ *  as published by the Free Software Foundation; either version 2
++ *  of the License, or (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include "dialog.h"
++
++unsigned char dialog_input_result[MAX_LEN + 1];
++
++/*
++ *  Print the termination buttons
++ */
++static void
++print_buttons(WINDOW *dialog, int height, int width, int selected)
++{
++    int x = width / 2 - 11;
++    int y = height - 2;
++
++    print_button (dialog, "  Ok  ", y, x, selected==0);
++    print_button (dialog, " Help ", y, x + 14, selected==1);
++
++    wmove(dialog, y, x+1+14*selected);
++    wrefresh(dialog);
++}
++
++/*
++ * Display a dialog box for inputing a string
++ */
++int
++dialog_inputbox (const char *title, const char *prompt, int height, int width,
++               const char *init)
++{
++    int i, x, y, box_y, box_x, box_width;
++    int input_x = 0, scroll = 0, key = 0, button = -1;
++    unsigned char *instr = dialog_input_result;
++    WINDOW *dialog;
++
++    /* center dialog box on screen */
++    x = (COLS - width) / 2;
++    y = (LINES - height) / 2;
++
++
++    draw_shadow (stdscr, y, x, height, width);
++
++    dialog = newwin (height, width, y, x);
++    keypad (dialog, TRUE);
++
++    draw_box (dialog, 0, 0, height, width, dialog_attr, border_attr);
++    wattrset (dialog, border_attr);
++    mvwaddch (dialog, height-3, 0, ACS_LTEE);
++    for (i = 0; i < width - 2; i++)
++      waddch (dialog, ACS_HLINE);
++    wattrset (dialog, dialog_attr);
++    waddch (dialog, ACS_RTEE);
++
++    if (title != NULL && strlen(title) >= width-2 ) {
++      /* truncate long title -- mec */
++      char * title2 = malloc(width-2+1);
++      memcpy( title2, title, width-2 );
++      title2[width-2] = '\0';
++      title = title2;
++    }
++
++    if (title != NULL) {
++      wattrset (dialog, title_attr);
++      mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' ');
++      waddstr (dialog, (char *)title);
++      waddch (dialog, ' ');
++    }
++
++    wattrset (dialog, dialog_attr);
++    print_autowrap (dialog, prompt, width - 2, 1, 3);
++
++    /* Draw the input field box */
++    box_width = width - 6;
++    getyx (dialog, y, x);
++    box_y = y + 2;
++    box_x = (width - box_width) / 2;
++    draw_box (dialog, y + 1, box_x - 1, 3, box_width + 2,
++            border_attr, dialog_attr);
++
++    print_buttons(dialog, height, width, 0);
++
++    /* Set up the initial value */
++    wmove (dialog, box_y, box_x);
++    wattrset (dialog, inputbox_attr);
++
++    if (!init)
++      instr[0] = '\0';
++    else
++      strcpy (instr, init);
++
++    input_x = strlen (instr);
++
++    if (input_x >= box_width) {
++      scroll = input_x - box_width + 1;
++      input_x = box_width - 1;
++      for (i = 0; i < box_width - 1; i++)
++          waddch (dialog, instr[scroll + i]);
++    } else
++      waddstr (dialog, instr);
++
++    wmove (dialog, box_y, box_x + input_x);
++
++    wrefresh (dialog);
++
++    while (key != ESC) {
++      key = wgetch (dialog);
++
++      if (button == -1) {     /* Input box selected */
++          switch (key) {
++          case TAB:
++          case KEY_UP:
++          case KEY_DOWN:
++              break;
++          case KEY_LEFT:
++              continue;
++          case KEY_RIGHT:
++              continue;
++          case KEY_BACKSPACE:
++          case 127:
++              if (input_x || scroll) {
++                  wattrset (dialog, inputbox_attr);
++                  if (!input_x) {
++                      scroll = scroll < box_width - 1 ?
++                          0 : scroll - (box_width - 1);
++                      wmove (dialog, box_y, box_x);
++                      for (i = 0; i < box_width; i++)
++                          waddch (dialog, instr[scroll + input_x + i] ?
++                                  instr[scroll + input_x + i] : ' ');
++                      input_x = strlen (instr) - scroll;
++                  } else
++                      input_x--;
++                  instr[scroll + input_x] = '\0';
++                  mvwaddch (dialog, box_y, input_x + box_x, ' ');
++                  wmove (dialog, box_y, input_x + box_x);
++                  wrefresh (dialog);
++              }
++              continue;
++          default:
++              if (key < 0x100 && isprint (key)) {
++                  if (scroll + input_x < MAX_LEN) {
++                      wattrset (dialog, inputbox_attr);
++                      instr[scroll + input_x] = key;
++                      instr[scroll + input_x + 1] = '\0';
++                      if (input_x == box_width - 1) {
++                          scroll++;
++                          wmove (dialog, box_y, box_x);
++                          for (i = 0; i < box_width - 1; i++)
++                              waddch (dialog, instr[scroll + i]);
++                      } else {
++                          wmove (dialog, box_y, input_x++ + box_x);
++                          waddch (dialog, key);
++                      }
++                      wrefresh (dialog);
++                  } else
++                      flash ();       /* Alarm user about overflow */
++                  continue;
++              }
++          }
++      }
++      switch (key) {
++      case 'O':
++      case 'o':
++          delwin (dialog);
++          return 0;
++      case 'H':
++      case 'h':
++          delwin (dialog);
++          return 1;
++      case KEY_UP:
++      case KEY_LEFT:
++          switch (button) {
++          case -1:
++              button = 1;     /* Indicates "Cancel" button is selected */
++              print_buttons(dialog, height, width, 1);
++              break;
++          case 0:
++              button = -1;    /* Indicates input box is selected */
++              print_buttons(dialog, height, width, 0);
++              wmove (dialog, box_y, box_x + input_x);
++              wrefresh (dialog);
++              break;
++          case 1:
++              button = 0;     /* Indicates "OK" button is selected */
++              print_buttons(dialog, height, width, 0);
++              break;
++          }
++          break;
++      case TAB:
++      case KEY_DOWN:
++      case KEY_RIGHT:
++          switch (button) {
++          case -1:
++              button = 0;     /* Indicates "OK" button is selected */
++              print_buttons(dialog, height, width, 0);
++              break;
++          case 0:
++              button = 1;     /* Indicates "Cancel" button is selected */
++              print_buttons(dialog, height, width, 1);
++              break;
++          case 1:
++              button = -1;    /* Indicates input box is selected */
++              print_buttons(dialog, height, width, 0);
++              wmove (dialog, box_y, box_x + input_x);
++              wrefresh (dialog);
++              break;
++          }
++          break;
++      case ' ':
++      case '\n':
++          delwin (dialog);
++          return (button == -1 ? 0 : button);
++      case 'X':
++      case 'x':
++          key = ESC;
++      case ESC:
++          break;
++      }
++    }
++
++    delwin (dialog);
++    return -1;                        /* ESC pressed */
++}
+diff -Nur busybox-1.00/scripts/config/lxdialog/menubox.c busybox/scripts/config/lxdialog/menubox.c
+--- busybox-1.00/scripts/config/lxdialog/menubox.c     1970-01-01 01:00:00.000000000 +0100
++++ busybox/scripts/config/lxdialog/menubox.c  2005-06-04 08:20:02.000000000 +0200
+@@ -0,0 +1,438 @@
++/*
++ *  menubox.c -- implements the menu box
++ *
++ *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
++ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw@cfw.com)
++ *
++ *  This program is free software; you can redistribute it and/or
++ *  modify it under the terms of the GNU General Public License
++ *  as published by the Free Software Foundation; either version 2
++ *  of the License, or (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++/*
++ *  Changes by Clifford Wolf (god@clifford.at)
++ *
++ *  [ 1998-06-13 ]
++ *
++ *    *)  A bugfix for the Page-Down problem
++ *
++ *    *)  Formerly when I used Page Down and Page Up, the cursor would be set 
++ *        to the first position in the menu box.  Now lxdialog is a bit
++ *        smarter and works more like other menu systems (just have a look at
++ *        it).
++ *
++ *    *)  Formerly if I selected something my scrolling would be broken because
++ *        lxdialog is re-invoked by the Menuconfig shell script, can't
++ *        remember the last scrolling position, and just sets it so that the
++ *        cursor is at the bottom of the box.  Now it writes the temporary file
++ *        lxdialog.scrltmp which contains this information. The file is
++ *        deleted by lxdialog if the user leaves a submenu or enters a new
++ *        one, but it would be nice if Menuconfig could make another "rm -f"
++ *        just to be sure.  Just try it out - you will recognise a difference!
++ *
++ *  [ 1998-06-14 ]
++ *
++ *    *)  Now lxdialog is crash-safe against broken "lxdialog.scrltmp" files
++ *        and menus change their size on the fly.
++ *
++ *    *)  If for some reason the last scrolling position is not saved by
++ *        lxdialog, it sets the scrolling so that the selected item is in the
++ *        middle of the menu box, not at the bottom.
++ *
++ * 02 January 1999, Michael Elizabeth Chastain (mec@shout.net)
++ * Reset 'scroll' to 0 if the value from lxdialog.scrltmp is bogus.
++ * This fixes a bug in Menuconfig where using ' ' to descend into menus
++ * would leave mis-synchronized lxdialog.scrltmp files lying around,
++ * fscanf would read in 'scroll', and eventually that value would get used.
++ */
++
++#include "dialog.h"
++
++static int menu_width, item_x;
++
++/*
++ * Print menu item
++ */
++static void
++print_item (WINDOW * win, const char *item, int choice, int selected, int hotkey)
++{
++    int j;
++    char menu_item[menu_width+1];
++
++    strncpy(menu_item, item, menu_width);
++    menu_item[menu_width] = 0;
++    j = first_alpha(menu_item, "YyNnMmHh");
++
++    /* Clear 'residue' of last item */
++    wattrset (win, menubox_attr);
++    wmove (win, choice, 0);
++#if OLD_NCURSES
++    {
++        int i;
++        for (i = 0; i < menu_width; i++)
++          waddch (win, ' ');
++    }
++#else
++    wclrtoeol(win);
++#endif
++    wattrset (win, selected ? item_selected_attr : item_attr);
++    mvwaddstr (win, choice, item_x, menu_item);
++    if (hotkey) {
++      wattrset (win, selected ? tag_key_selected_attr : tag_key_attr);
++      mvwaddch(win, choice, item_x+j, menu_item[j]);
++    }
++    if (selected) {
++      wmove (win, choice, item_x+1);
++      wrefresh (win);
++    }
++}
++
++/*
++ * Print the scroll indicators.
++ */
++static void
++print_arrows (WINDOW * win, int item_no, int scroll,
++              int y, int x, int height)
++{
++    int cur_y, cur_x;
++
++    getyx(win, cur_y, cur_x);
++
++    wmove(win, y, x);
++
++    if (scroll > 0) {
++      wattrset (win, uarrow_attr);
++      waddch (win, ACS_UARROW);
++      waddstr (win, "(-)");
++    }
++    else {
++      wattrset (win, menubox_attr);
++      waddch (win, ACS_HLINE);
++      waddch (win, ACS_HLINE);
++      waddch (win, ACS_HLINE);
++      waddch (win, ACS_HLINE);
++    }
++
++   y = y + height + 1;
++   wmove(win, y, x);
++
++   if ((height < item_no) && (scroll + height < item_no)) {
++      wattrset (win, darrow_attr);
++      waddch (win, ACS_DARROW);
++      waddstr (win, "(+)");
++    }
++    else {
++      wattrset (win, menubox_border_attr);
++      waddch (win, ACS_HLINE);
++      waddch (win, ACS_HLINE);
++      waddch (win, ACS_HLINE);
++      waddch (win, ACS_HLINE);
++   }
++
++   wmove(win, cur_y, cur_x);
++}
++
++/*
++ * Display the termination buttons.
++ */
++static void
++print_buttons (WINDOW *win, int height, int width, int selected)
++{
++    int x = width / 2 - 16;
++    int y = height - 2;
++
++    print_button (win, "Select", y, x, selected == 0);
++    print_button (win, " Exit ", y, x + 12, selected == 1);
++    print_button (win, " Help ", y, x + 24, selected == 2);
++
++    wmove(win, y, x+1+12*selected);
++    wrefresh (win);
++}
++
++/*
++ * Display a menu for choosing among a number of options
++ */
++int
++dialog_menu (const char *title, const char *prompt, int height, int width,
++              int menu_height, const char *current, int item_no,
++              struct dialog_list_item ** items)
++{
++    int i, j, x, y, box_x, box_y;
++    int key = 0, button = 0, scroll = 0, choice = 0, first_item = 0, max_choice;
++    WINDOW *dialog, *menu;
++    FILE *f;
++
++    max_choice = MIN (menu_height, item_no);
++
++    /* center dialog box on screen */
++    x = (COLS - width) / 2;
++    y = (LINES - height) / 2;
++
++    draw_shadow (stdscr, y, x, height, width);
++
++    dialog = newwin (height, width, y, x);
++    keypad (dialog, TRUE);
++
++    draw_box (dialog, 0, 0, height, width, dialog_attr, border_attr);
++    wattrset (dialog, border_attr);
++    mvwaddch (dialog, height - 3, 0, ACS_LTEE);
++    for (i = 0; i < width - 2; i++)
++      waddch (dialog, ACS_HLINE);
++    wattrset (dialog, dialog_attr);
++    wbkgdset (dialog, dialog_attr & A_COLOR);
++    waddch (dialog, ACS_RTEE);
++
++    if (title != NULL && strlen(title) >= width-2 ) {
++      /* truncate long title -- mec */
++      char * title2 = malloc(width-2+1);
++      memcpy( title2, title, width-2 );
++      title2[width-2] = '\0';
++      title = title2;
++    }
++
++    if (title != NULL) {
++      wattrset (dialog, title_attr);
++      mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' ');
++      waddstr (dialog, (char *)title);
++      waddch (dialog, ' ');
++    }
++
++    wattrset (dialog, dialog_attr);
++    print_autowrap (dialog, prompt, width - 2, 1, 3);
++
++    menu_width = width - 6;
++    box_y = height - menu_height - 5;
++    box_x = (width - menu_width) / 2 - 1;
++
++    /* create new window for the menu */
++    menu = subwin (dialog, menu_height, menu_width,
++              y + box_y + 1, x + box_x + 1);
++    keypad (menu, TRUE);
++
++    /* draw a box around the menu items */
++    draw_box (dialog, box_y, box_x, menu_height + 2, menu_width + 2,
++            menubox_border_attr, menubox_attr);
++
++    /*
++     * Find length of longest item in order to center menu.
++     * Set 'choice' to default item. 
++     */
++    item_x = 0;
++    for (i = 0; i < item_no; i++) {
++      item_x = MAX (item_x, MIN(menu_width, strlen (items[i]->name) + 2));
++      if (strcmp(current, items[i]->tag) == 0) choice = i;
++    }
++
++    item_x = (menu_width - item_x) / 2;
++
++    /* get the scroll info from the temp file */
++    if ( (f=fopen("lxdialog.scrltmp","r")) != NULL ) {
++      if ( (fscanf(f,"%d\n",&scroll) == 1) && (scroll <= choice) &&
++           (scroll+max_choice > choice) && (scroll >= 0) &&
++           (scroll+max_choice <= item_no) ) {
++          first_item = scroll;
++          choice = choice - scroll;
++          fclose(f);
++      } else {
++          scroll=0;
++          remove("lxdialog.scrltmp");
++          fclose(f);
++          f=NULL;
++      }
++    }
++    if ( (choice >= max_choice) || (f==NULL && choice >= max_choice/2) ) {
++      if (choice >= item_no-max_choice/2)
++          scroll = first_item = item_no-max_choice;
++      else
++          scroll = first_item = choice - max_choice/2;
++      choice = choice - scroll;
++    }
++
++    /* Print the menu */
++    for (i=0; i < max_choice; i++) {
++      print_item (menu, items[first_item + i]->name, i, i == choice,
++                    (items[first_item + i]->tag[0] != ':'));
++    }
++
++    wnoutrefresh (menu);
++
++    print_arrows(dialog, item_no, scroll,
++               box_y, box_x+item_x+1, menu_height);
++
++    print_buttons (dialog, height, width, 0);
++    wmove (menu, choice, item_x+1);
++    wrefresh (menu);
++
++    while (key != ESC) {
++      key = wgetch(menu);
++
++      if (key < 256 && isalpha(key)) key = tolower(key);
++
++      if (strchr("ynmh", key))
++              i = max_choice;
++      else {
++        for (i = choice+1; i < max_choice; i++) {
++              j = first_alpha(items[scroll + i]->name, "YyNnMmHh");
++              if (key == tolower(items[scroll + i]->name[j]))
++                      break;
++      }
++      if (i == max_choice)
++                      for (i = 0; i < max_choice; i++) {
++                      j = first_alpha(items[scroll + i]->name, "YyNnMmHh");
++                      if (key == tolower(items[scroll + i]->name[j]))
++                              break;
++              }
++      }
++
++      if (i < max_choice || 
++            key == KEY_UP || key == KEY_DOWN ||
++            key == '-' || key == '+' ||
++            key == KEY_PPAGE || key == KEY_NPAGE) {
++
++            print_item (menu, items[scroll + choice]->name, choice, FALSE,
++                       (items[scroll + choice]->tag[0] != ':'));
++
++          if (key == KEY_UP || key == '-') {
++                if (choice < 2 && scroll) {
++                  /* Scroll menu down */
++                    scrollok (menu, TRUE);
++                    wscrl (menu, -1);
++                    scrollok (menu, FALSE);
++
++                    scroll--;
++
++                    print_item (menu, items[scroll]->name, 0, FALSE,
++                               (items[scroll]->tag[0] != ':'));
++              } else
++                  choice = MAX(choice - 1, 0);
++
++          } else if (key == KEY_DOWN || key == '+')  {
++
++              print_item (menu, items[scroll + choice]->name, choice, FALSE,
++                                (items[scroll + choice]->tag[0] != ':'));
++
++                if ((choice > max_choice-3) &&
++                    (scroll + max_choice < item_no)
++                   ) {
++                  /* Scroll menu up */
++                  scrollok (menu, TRUE);
++                    scroll (menu);
++                    scrollok (menu, FALSE);
++
++                    scroll++;
++
++                    print_item (menu, items[scroll + max_choice - 1]->name,
++                               max_choice-1, FALSE,
++                               (items[scroll + max_choice - 1]->tag[0] != ':'));
++                } else
++                    choice = MIN(choice+1, max_choice-1);
++
++          } else if (key == KEY_PPAGE) {
++              scrollok (menu, TRUE);
++                for (i=0; (i < max_choice); i++) {
++                    if (scroll > 0) {
++                      wscrl (menu, -1);
++                      scroll--;
++                      print_item (menu, items[scroll]->name, 0, FALSE,
++                      (items[scroll]->tag[0] != ':'));
++                    } else {
++                        if (choice > 0)
++                            choice--;
++                    }
++                }
++                scrollok (menu, FALSE);
++
++            } else if (key == KEY_NPAGE) {
++                for (i=0; (i < max_choice); i++) {
++                    if (scroll+max_choice < item_no) {
++                      scrollok (menu, TRUE);
++                      scroll(menu);
++                      scrollok (menu, FALSE);
++                      scroll++;
++                      print_item (menu, items[scroll + max_choice - 1]->name,
++                                  max_choice-1, FALSE,
++                                  (items[scroll + max_choice - 1]->tag[0] != ':'));
++                  } else {
++                      if (choice+1 < max_choice)
++                          choice++;
++                  }
++                }
++
++            } else
++                choice = i;
++
++            print_item (menu, items[scroll + choice]->name, choice, TRUE,
++                       (items[scroll + choice]->tag[0] != ':'));
++
++            print_arrows(dialog, item_no, scroll,
++                         box_y, box_x+item_x+1, menu_height);
++
++            wnoutrefresh (dialog);
++            wrefresh (menu);
++
++          continue;           /* wait for another key press */
++        }
++
++      switch (key) {
++      case KEY_LEFT:
++      case TAB:
++      case KEY_RIGHT:
++          button = ((key == KEY_LEFT ? --button : ++button) < 0)
++                      ? 2 : (button > 2 ? 0 : button);
++
++          print_buttons(dialog, height, width, button);
++          wrefresh (menu);
++          break;
++      case ' ':
++      case 's':
++      case 'y':
++      case 'n':
++      case 'm':
++      case '/':
++          /* save scroll info */
++          if ( (f=fopen("lxdialog.scrltmp","w")) != NULL ) {
++              fprintf(f,"%d\n",scroll);
++              fclose(f);
++          }
++          delwin (dialog);
++            items[scroll + choice]->selected = 1;
++            switch (key) {
++            case 's': return 3;
++            case 'y': return 3;
++            case 'n': return 4;
++            case 'm': return 5;
++            case ' ': return 6;
++            case '/': return 7;
++            }
++          return 0;
++      case 'h':
++      case '?':
++          button = 2;
++      case '\n':
++          delwin (dialog);
++          items[scroll + choice]->selected = 1;
++
++          remove("lxdialog.scrltmp");
++          return button;
++      case 'e':
++      case 'x':
++          key = ESC;
++      case ESC:
++          break;
++      }
++    }
++
++    delwin (dialog);
++    remove("lxdialog.scrltmp");
++    return -1;                        /* ESC pressed */
++}
+diff -Nur busybox-1.00/scripts/config/lxdialog/msgbox.c busybox/scripts/config/lxdialog/msgbox.c
+--- busybox-1.00/scripts/config/lxdialog/msgbox.c      1970-01-01 01:00:00.000000000 +0100
++++ busybox/scripts/config/lxdialog/msgbox.c   2005-06-04 08:20:02.000000000 +0200
+@@ -0,0 +1,85 @@
++/*
++ *  msgbox.c -- implements the message box and info box
++ *
++ *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
++ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw@cfw.com)
++ *
++ *  This program is free software; you can redistribute it and/or
++ *  modify it under the terms of the GNU General Public License
++ *  as published by the Free Software Foundation; either version 2
++ *  of the License, or (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include "dialog.h"
++
++/*
++ * Display a message box. Program will pause and display an "OK" button
++ * if the parameter 'pause' is non-zero.
++ */
++int
++dialog_msgbox (const char *title, const char *prompt, int height, int width,
++              int pause)
++{
++    int i, x, y, key = 0;
++    WINDOW *dialog;
++
++    /* center dialog box on screen */
++    x = (COLS - width) / 2;
++    y = (LINES - height) / 2;
++
++    draw_shadow (stdscr, y, x, height, width);
++
++    dialog = newwin (height, width, y, x);
++    keypad (dialog, TRUE);
++
++    draw_box (dialog, 0, 0, height, width, dialog_attr, border_attr);
++
++    if (title != NULL && strlen(title) >= width-2 ) {
++      /* truncate long title -- mec */
++      char * title2 = malloc(width-2+1);
++      memcpy( title2, title, width-2 );
++      title2[width-2] = '\0';
++      title = title2;
++    }
++
++    if (title != NULL) {
++      wattrset (dialog, title_attr);
++      mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' ');
++      waddstr (dialog, (char *)title);
++      waddch (dialog, ' ');
++    }
++    wattrset (dialog, dialog_attr);
++    print_autowrap (dialog, prompt, width - 2, 1, 2);
++
++    if (pause) {
++      wattrset (dialog, border_attr);
++      mvwaddch (dialog, height - 3, 0, ACS_LTEE);
++      for (i = 0; i < width - 2; i++)
++          waddch (dialog, ACS_HLINE);
++      wattrset (dialog, dialog_attr);
++      waddch (dialog, ACS_RTEE);
++
++      print_button (dialog, "  Ok  ",
++                    height - 2, width / 2 - 4, TRUE);
++
++      wrefresh (dialog);
++      while (key != ESC && key != '\n' && key != ' ' &&
++               key != 'O' && key != 'o' && key != 'X' && key != 'x')
++          key = wgetch (dialog);
++    } else {
++      key = '\n';
++      wrefresh (dialog);
++    }
++
++    delwin (dialog);
++    return key == ESC ? -1 : 0;
++}
+diff -Nur busybox-1.00/scripts/config/lxdialog/textbox.c busybox/scripts/config/lxdialog/textbox.c
+--- busybox-1.00/scripts/config/lxdialog/textbox.c     1970-01-01 01:00:00.000000000 +0100
++++ busybox/scripts/config/lxdialog/textbox.c  2005-06-04 08:20:02.000000000 +0200
+@@ -0,0 +1,556 @@
++/*
++ *  textbox.c -- implements the text box
++ *
++ *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
++ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
++ *
++ *  This program is free software; you can redistribute it and/or
++ *  modify it under the terms of the GNU General Public License
++ *  as published by the Free Software Foundation; either version 2
++ *  of the License, or (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include "dialog.h"
++
++static void back_lines (int n);
++static void print_page (WINDOW * win, int height, int width);
++static void print_line (WINDOW * win, int row, int width);
++static char *get_line (void);
++static void print_position (WINDOW * win, int height, int width);
++
++static int hscroll, fd, file_size, bytes_read;
++static int begin_reached = 1, end_reached, page_length;
++static char *buf, *page;
++
++/*
++ * Display text from a file in a dialog box.
++ */
++int
++dialog_textbox (const char *title, const char *file, int height, int width)
++{
++    int i, x, y, cur_x, cur_y, fpos, key = 0;
++    int passed_end;
++    char search_term[MAX_LEN + 1];
++    WINDOW *dialog, *text;
++
++    search_term[0] = '\0';    /* no search term entered yet */
++
++    /* Open input file for reading */
++    if ((fd = open (file, O_RDONLY)) == -1) {
++      endwin ();
++      fprintf (stderr,
++               "\nCan't open input file in dialog_textbox().\n");
++      exit (-1);
++    }
++    /* Get file size. Actually, 'file_size' is the real file size - 1,
++       since it's only the last byte offset from the beginning */
++    if ((file_size = lseek (fd, 0, SEEK_END)) == -1) {
++      endwin ();
++      fprintf (stderr, "\nError getting file size in dialog_textbox().\n");
++      exit (-1);
++    }
++    /* Restore file pointer to beginning of file after getting file size */
++    if (lseek (fd, 0, SEEK_SET) == -1) {
++      endwin ();
++      fprintf (stderr, "\nError moving file pointer in dialog_textbox().\n");
++      exit (-1);
++    }
++    /* Allocate space for read buffer */
++    if ((buf = malloc (BUF_SIZE + 1)) == NULL) {
++      endwin ();
++      fprintf (stderr, "\nCan't allocate memory in dialog_textbox().\n");
++      exit (-1);
++    }
++    if ((bytes_read = read (fd, buf, BUF_SIZE)) == -1) {
++      endwin ();
++      fprintf (stderr, "\nError reading file in dialog_textbox().\n");
++      exit (-1);
++    }
++    buf[bytes_read] = '\0';   /* mark end of valid data */
++    page = buf;                       /* page is pointer to start of page to be displayed */
++
++    /* center dialog box on screen */
++    x = (COLS - width) / 2;
++    y = (LINES - height) / 2;
++
++
++    draw_shadow (stdscr, y, x, height, width);
++
++    dialog = newwin (height, width, y, x);
++    keypad (dialog, TRUE);
++
++    /* Create window for text region, used for scrolling text */
++    text = subwin (dialog, height - 4, width - 2, y + 1, x + 1);
++    wattrset (text, dialog_attr);
++    wbkgdset (text, dialog_attr & A_COLOR);
++
++    keypad (text, TRUE);
++
++    /* register the new window, along with its borders */
++    draw_box (dialog, 0, 0, height, width, dialog_attr, border_attr);
++
++    wattrset (dialog, border_attr);
++    mvwaddch (dialog, height-3, 0, ACS_LTEE);
++    for (i = 0; i < width - 2; i++)
++      waddch (dialog, ACS_HLINE);
++    wattrset (dialog, dialog_attr);
++    wbkgdset (dialog, dialog_attr & A_COLOR);
++    waddch (dialog, ACS_RTEE);
++
++    if (title != NULL && strlen(title) >= width-2 ) {
++      /* truncate long title -- mec */
++      char * title2 = malloc(width-2+1);
++      memcpy( title2, title, width-2 );
++      title2[width-2] = '\0';
++      title = title2;
++    }
++
++    if (title != NULL) {
++      wattrset (dialog, title_attr);
++      mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' ');
++      waddstr (dialog, (char *)title);
++      waddch (dialog, ' ');
++    }
++    print_button (dialog, " Exit ", height - 2, width / 2 - 4, TRUE);
++    wnoutrefresh (dialog);
++    getyx (dialog, cur_y, cur_x);     /* Save cursor position */
++
++    /* Print first page of text */
++    attr_clear (text, height - 4, width - 2, dialog_attr);
++    print_page (text, height - 4, width - 2);
++    print_position (dialog, height, width);
++    wmove (dialog, cur_y, cur_x);     /* Restore cursor position */
++    wrefresh (dialog);
++
++    while ((key != ESC) && (key != '\n')) {
++      key = wgetch (dialog);
++      switch (key) {
++      case 'E':               /* Exit */
++      case 'e':
++      case 'X':
++      case 'x':
++          delwin (dialog);
++          free (buf);
++          close (fd);
++          return 0;
++      case 'g':               /* First page */
++      case KEY_HOME:
++          if (!begin_reached) {
++              begin_reached = 1;
++              /* First page not in buffer? */
++              if ((fpos = lseek (fd, 0, SEEK_CUR)) == -1) {
++                  endwin ();
++                  fprintf (stderr,
++                    "\nError moving file pointer in dialog_textbox().\n");
++                  exit (-1);
++              }
++              if (fpos > bytes_read) {        /* Yes, we have to read it in */
++                  if (lseek (fd, 0, SEEK_SET) == -1) {
++                      endwin ();
++                      fprintf (stderr, "\nError moving file pointer in "
++                               "dialog_textbox().\n");
++                      exit (-1);
++                  }
++                  if ((bytes_read = read (fd, buf, BUF_SIZE)) == -1) {
++                      endwin ();
++                      fprintf (stderr,
++                           "\nError reading file in dialog_textbox().\n");
++                      exit (-1);
++                  }
++                  buf[bytes_read] = '\0';
++              }
++              page = buf;
++              print_page (text, height - 4, width - 2);
++              print_position (dialog, height, width);
++              wmove (dialog, cur_y, cur_x);   /* Restore cursor position */
++              wrefresh (dialog);
++          }
++          break;
++      case 'G':               /* Last page */
++      case KEY_END:
++
++          end_reached = 1;
++          /* Last page not in buffer? */
++          if ((fpos = lseek (fd, 0, SEEK_CUR)) == -1) {
++              endwin ();
++              fprintf (stderr,
++                    "\nError moving file pointer in dialog_textbox().\n");
++              exit (-1);
++          }
++          if (fpos < file_size) {     /* Yes, we have to read it in */
++              if (lseek (fd, -BUF_SIZE, SEEK_END) == -1) {
++                  endwin ();
++                  fprintf (stderr,
++                    "\nError moving file pointer in dialog_textbox().\n");
++                  exit (-1);
++              }
++              if ((bytes_read = read (fd, buf, BUF_SIZE)) == -1) {
++                  endwin ();
++                  fprintf (stderr,
++                           "\nError reading file in dialog_textbox().\n");
++                  exit (-1);
++              }
++              buf[bytes_read] = '\0';
++          }
++          page = buf + bytes_read;
++          back_lines (height - 4);
++          print_page (text, height - 4, width - 2);
++          print_position (dialog, height, width);
++          wmove (dialog, cur_y, cur_x);       /* Restore cursor position */
++          wrefresh (dialog);
++          break;
++      case 'K':               /* Previous line */
++      case 'k':
++      case KEY_UP:
++          if (!begin_reached) {
++              back_lines (page_length + 1);
++
++              /* We don't call print_page() here but use scrolling to ensure
++                 faster screen update. However, 'end_reached' and
++                 'page_length' should still be updated, and 'page' should
++                 point to start of next page. This is done by calling
++                 get_line() in the following 'for' loop. */
++              scrollok (text, TRUE);
++              wscrl (text, -1);       /* Scroll text region down one line */
++              scrollok (text, FALSE);
++              page_length = 0;
++              passed_end = 0;
++              for (i = 0; i < height - 4; i++) {
++                  if (!i) {
++                      /* print first line of page */
++                      print_line (text, 0, width - 2);
++                      wnoutrefresh (text);
++                  } else
++                      /* Called to update 'end_reached' and 'page' */
++                      get_line ();
++                  if (!passed_end)
++                      page_length++;
++                  if (end_reached && !passed_end)
++                      passed_end = 1;
++              }
++
++              print_position (dialog, height, width);
++              wmove (dialog, cur_y, cur_x);   /* Restore cursor position */
++              wrefresh (dialog);
++          }
++          break;
++      case 'B':               /* Previous page */
++      case 'b':
++      case KEY_PPAGE:
++          if (begin_reached)
++              break;
++          back_lines (page_length + height - 4);
++          print_page (text, height - 4, width - 2);
++          print_position (dialog, height, width);
++          wmove (dialog, cur_y, cur_x);
++          wrefresh (dialog);
++          break;
++      case 'J':               /* Next line */
++      case 'j':
++      case KEY_DOWN:
++          if (!end_reached) {
++              begin_reached = 0;
++              scrollok (text, TRUE);
++              scroll (text);  /* Scroll text region up one line */
++              scrollok (text, FALSE);
++              print_line (text, height - 5, width - 2);
++              wnoutrefresh (text);
++              print_position (dialog, height, width);
++              wmove (dialog, cur_y, cur_x);   /* Restore cursor position */
++              wrefresh (dialog);
++          }
++          break;
++      case KEY_NPAGE:         /* Next page */
++      case ' ':
++          if (end_reached)
++              break;
++
++          begin_reached = 0;
++          print_page (text, height - 4, width - 2);
++          print_position (dialog, height, width);
++          wmove (dialog, cur_y, cur_x);
++          wrefresh (dialog);
++          break;
++      case '0':               /* Beginning of line */
++      case 'H':               /* Scroll left */
++      case 'h':
++      case KEY_LEFT:
++          if (hscroll <= 0)
++              break;
++
++          if (key == '0')
++              hscroll = 0;
++          else
++              hscroll--;
++          /* Reprint current page to scroll horizontally */
++          back_lines (page_length);
++          print_page (text, height - 4, width - 2);
++          wmove (dialog, cur_y, cur_x);
++          wrefresh (dialog);
++          break;
++      case 'L':               /* Scroll right */
++      case 'l':
++      case KEY_RIGHT:
++          if (hscroll >= MAX_LEN)
++              break;
++          hscroll++;
++          /* Reprint current page to scroll horizontally */
++          back_lines (page_length);
++          print_page (text, height - 4, width - 2);
++          wmove (dialog, cur_y, cur_x);
++          wrefresh (dialog);
++          break;
++      case ESC:
++          break;
++      }
++    }
++
++    delwin (dialog);
++    free (buf);
++    close (fd);
++    return 1;                 /* ESC pressed */
++}
++
++/*
++ * Go back 'n' lines in text file. Called by dialog_textbox().
++ * 'page' will be updated to point to the desired line in 'buf'.
++ */
++static void
++back_lines (int n)
++{
++    int i, fpos;
++
++    begin_reached = 0;
++    /* We have to distinguish between end_reached and !end_reached
++       since at end of file, the line is not ended by a '\n'.
++       The code inside 'if' basically does a '--page' to move one
++       character backward so as to skip '\n' of the previous line */
++    if (!end_reached) {
++      /* Either beginning of buffer or beginning of file reached? */
++      if (page == buf) {
++          if ((fpos = lseek (fd, 0, SEEK_CUR)) == -1) {
++              endwin ();
++              fprintf (stderr, "\nError moving file pointer in "
++                       "back_lines().\n");
++              exit (-1);
++          }
++          if (fpos > bytes_read) {    /* Not beginning of file yet */
++              /* We've reached beginning of buffer, but not beginning of
++                 file yet, so read previous part of file into buffer.
++                 Note that we only move backward for BUF_SIZE/2 bytes,
++                 but not BUF_SIZE bytes to avoid re-reading again in
++                 print_page() later */
++              /* Really possible to move backward BUF_SIZE/2 bytes? */
++              if (fpos < BUF_SIZE / 2 + bytes_read) {
++                  /* No, move less then */
++                  if (lseek (fd, 0, SEEK_SET) == -1) {
++                      endwin ();
++                      fprintf (stderr, "\nError moving file pointer in "
++                               "back_lines().\n");
++                      exit (-1);
++                  }
++                  page = buf + fpos - bytes_read;
++              } else {        /* Move backward BUF_SIZE/2 bytes */
++                  if (lseek (fd, -(BUF_SIZE / 2 + bytes_read), SEEK_CUR)
++                      == -1) {
++                      endwin ();
++                      fprintf (stderr, "\nError moving file pointer "
++                               "in back_lines().\n");
++                      exit (-1);
++                  }
++                  page = buf + BUF_SIZE / 2;
++              }
++              if ((bytes_read = read (fd, buf, BUF_SIZE)) == -1) {
++                  endwin ();
++                  fprintf (stderr, "\nError reading file in back_lines().\n");
++                  exit (-1);
++              }
++              buf[bytes_read] = '\0';
++          } else {            /* Beginning of file reached */
++              begin_reached = 1;
++              return;
++          }
++      }
++      if (*(--page) != '\n') {        /* '--page' here */
++          /* Something's wrong... */
++          endwin ();
++          fprintf (stderr, "\nInternal error in back_lines().\n");
++          exit (-1);
++      }
++    }
++    /* Go back 'n' lines */
++    for (i = 0; i < n; i++)
++      do {
++          if (page == buf) {
++              if ((fpos = lseek (fd, 0, SEEK_CUR)) == -1) {
++                  endwin ();
++                  fprintf (stderr,
++                        "\nError moving file pointer in back_lines().\n");
++                  exit (-1);
++              }
++              if (fpos > bytes_read) {
++                  /* Really possible to move backward BUF_SIZE/2 bytes? */
++                  if (fpos < BUF_SIZE / 2 + bytes_read) {
++                      /* No, move less then */
++                      if (lseek (fd, 0, SEEK_SET) == -1) {
++                          endwin ();
++                          fprintf (stderr, "\nError moving file pointer "
++                                   "in back_lines().\n");
++                          exit (-1);
++                      }
++                      page = buf + fpos - bytes_read;
++                  } else {    /* Move backward BUF_SIZE/2 bytes */
++                      if (lseek (fd, -(BUF_SIZE / 2 + bytes_read),
++                                 SEEK_CUR) == -1) {
++                          endwin ();
++                          fprintf (stderr, "\nError moving file pointer"
++                                   " in back_lines().\n");
++                          exit (-1);
++                      }
++                      page = buf + BUF_SIZE / 2;
++                  }
++                  if ((bytes_read = read (fd, buf, BUF_SIZE)) == -1) {
++                      endwin ();
++                      fprintf (stderr, "\nError reading file in "
++                               "back_lines().\n");
++                      exit (-1);
++                  }
++                  buf[bytes_read] = '\0';
++              } else {        /* Beginning of file reached */
++                  begin_reached = 1;
++                  return;
++              }
++          }
++      } while (*(--page) != '\n');
++    page++;
++}
++
++/*
++ * Print a new page of text. Called by dialog_textbox().
++ */
++static void
++print_page (WINDOW * win, int height, int width)
++{
++    int i, passed_end = 0;
++
++    page_length = 0;
++    for (i = 0; i < height; i++) {
++      print_line (win, i, width);
++      if (!passed_end)
++          page_length++;
++      if (end_reached && !passed_end)
++          passed_end = 1;
++    }
++    wnoutrefresh (win);
++}
++
++/*
++ * Print a new line of text. Called by dialog_textbox() and print_page().
++ */
++static void
++print_line (WINDOW * win, int row, int width)
++{
++    int y, x;
++    char *line;
++
++    line = get_line ();
++    line += MIN (strlen (line), hscroll);     /* Scroll horizontally */
++    wmove (win, row, 0);      /* move cursor to correct line */
++    waddch (win, ' ');
++    waddnstr (win, line, MIN (strlen (line), width - 2));
++
++    getyx (win, y, x);
++    /* Clear 'residue' of previous line */
++#if OLD_NCURSES
++    {
++        int i;
++        for (i = 0; i < width - x; i++)
++          waddch (win, ' ');
++    }
++#else
++    wclrtoeol(win);
++#endif
++}
++
++/*
++ * Return current line of text. Called by dialog_textbox() and print_line().
++ * 'page' should point to start of current line before calling, and will be
++ * updated to point to start of next line.
++ */
++static char *
++get_line (void)
++{
++    int i = 0, fpos;
++    static char line[MAX_LEN + 1];
++
++    end_reached = 0;
++    while (*page != '\n') {
++      if (*page == '\0') {
++          /* Either end of file or end of buffer reached */
++          if ((fpos = lseek (fd, 0, SEEK_CUR)) == -1) {
++              endwin ();
++              fprintf (stderr, "\nError moving file pointer in "
++                       "get_line().\n");
++              exit (-1);
++          }
++          if (fpos < file_size) {     /* Not end of file yet */
++              /* We've reached end of buffer, but not end of file yet,
++                 so read next part of file into buffer */
++              if ((bytes_read = read (fd, buf, BUF_SIZE)) == -1) {
++                  endwin ();
++                  fprintf (stderr, "\nError reading file in get_line().\n");
++                  exit (-1);
++              }
++              buf[bytes_read] = '\0';
++              page = buf;
++          } else {
++              if (!end_reached)
++                  end_reached = 1;
++              break;
++          }
++      } else if (i < MAX_LEN)
++          line[i++] = *(page++);
++      else {
++          /* Truncate lines longer than MAX_LEN characters */
++          if (i == MAX_LEN)
++              line[i++] = '\0';
++          page++;
++      }
++    }
++    if (i <= MAX_LEN)
++      line[i] = '\0';
++    if (!end_reached)
++      page++;                 /* move pass '\n' */
++
++    return line;
++}
++
++/*
++ * Print current position
++ */
++static void
++print_position (WINDOW * win, int height, int width)
++{
++    int fpos, percent;
++
++    if ((fpos = lseek (fd, 0, SEEK_CUR)) == -1) {
++      endwin ();
++      fprintf (stderr, "\nError moving file pointer in print_position().\n");
++      exit (-1);
++    }
++    wattrset (win, position_indicator_attr);
++    wbkgdset (win, position_indicator_attr & A_COLOR);
++    percent = !file_size ?
++      100 : ((fpos - bytes_read + page - buf) * 100) / file_size;
++    wmove (win, height - 3, width - 9);
++    wprintw (win, "(%3d%%)", percent);
++}
+diff -Nur busybox-1.00/scripts/config/lxdialog/util.c busybox/scripts/config/lxdialog/util.c
+--- busybox-1.00/scripts/config/lxdialog/util.c        1970-01-01 01:00:00.000000000 +0100
++++ busybox/scripts/config/lxdialog/util.c     2005-06-04 08:20:02.000000000 +0200
+@@ -0,0 +1,375 @@
++/*
++ *  util.c
++ *
++ *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
++ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
++ *
++ *  This program is free software; you can redistribute it and/or
++ *  modify it under the terms of the GNU General Public License
++ *  as published by the Free Software Foundation; either version 2
++ *  of the License, or (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include "dialog.h"
++
++
++/* use colors by default? */
++bool use_colors = 1;
++
++const char *backtitle = NULL;
++
++const char *dialog_result;
++
++/* 
++ * Attribute values, default is for mono display
++ */
++chtype attributes[] =
++{
++    A_NORMAL,                 /* screen_attr */
++    A_NORMAL,                 /* shadow_attr */
++    A_NORMAL,                 /* dialog_attr */
++    A_BOLD,                   /* title_attr */
++    A_NORMAL,                 /* border_attr */
++    A_REVERSE,                        /* button_active_attr */
++    A_DIM,                    /* button_inactive_attr */
++    A_REVERSE,                        /* button_key_active_attr */
++    A_BOLD,                   /* button_key_inactive_attr */
++    A_REVERSE,                        /* button_label_active_attr */
++    A_NORMAL,                 /* button_label_inactive_attr */
++    A_NORMAL,                 /* inputbox_attr */
++    A_NORMAL,                 /* inputbox_border_attr */
++    A_NORMAL,                 /* searchbox_attr */
++    A_BOLD,                   /* searchbox_title_attr */
++    A_NORMAL,                 /* searchbox_border_attr */
++    A_BOLD,                   /* position_indicator_attr */
++    A_NORMAL,                 /* menubox_attr */
++    A_NORMAL,                 /* menubox_border_attr */
++    A_NORMAL,                 /* item_attr */
++    A_REVERSE,                        /* item_selected_attr */
++    A_BOLD,                   /* tag_attr */
++    A_REVERSE,                        /* tag_selected_attr */
++    A_BOLD,                   /* tag_key_attr */
++    A_REVERSE,                        /* tag_key_selected_attr */
++    A_BOLD,                   /* check_attr */
++    A_REVERSE,                        /* check_selected_attr */
++    A_BOLD,                   /* uarrow_attr */
++    A_BOLD                    /* darrow_attr */
++};
++
++
++#include "colors.h"
++
++/*
++ * Table of color values
++ */
++int color_table[][3] =
++{
++    {SCREEN_FG, SCREEN_BG, SCREEN_HL},
++    {SHADOW_FG, SHADOW_BG, SHADOW_HL},
++    {DIALOG_FG, DIALOG_BG, DIALOG_HL},
++    {TITLE_FG, TITLE_BG, TITLE_HL},
++    {BORDER_FG, BORDER_BG, BORDER_HL},
++    {BUTTON_ACTIVE_FG, BUTTON_ACTIVE_BG, BUTTON_ACTIVE_HL},
++    {BUTTON_INACTIVE_FG, BUTTON_INACTIVE_BG, BUTTON_INACTIVE_HL},
++    {BUTTON_KEY_ACTIVE_FG, BUTTON_KEY_ACTIVE_BG, BUTTON_KEY_ACTIVE_HL},
++    {BUTTON_KEY_INACTIVE_FG, BUTTON_KEY_INACTIVE_BG, BUTTON_KEY_INACTIVE_HL},
++    {BUTTON_LABEL_ACTIVE_FG, BUTTON_LABEL_ACTIVE_BG, BUTTON_LABEL_ACTIVE_HL},
++    {BUTTON_LABEL_INACTIVE_FG, BUTTON_LABEL_INACTIVE_BG,
++     BUTTON_LABEL_INACTIVE_HL},
++    {INPUTBOX_FG, INPUTBOX_BG, INPUTBOX_HL},
++    {INPUTBOX_BORDER_FG, INPUTBOX_BORDER_BG, INPUTBOX_BORDER_HL},
++    {SEARCHBOX_FG, SEARCHBOX_BG, SEARCHBOX_HL},
++    {SEARCHBOX_TITLE_FG, SEARCHBOX_TITLE_BG, SEARCHBOX_TITLE_HL},
++    {SEARCHBOX_BORDER_FG, SEARCHBOX_BORDER_BG, SEARCHBOX_BORDER_HL},
++    {POSITION_INDICATOR_FG, POSITION_INDICATOR_BG, POSITION_INDICATOR_HL},
++    {MENUBOX_FG, MENUBOX_BG, MENUBOX_HL},
++    {MENUBOX_BORDER_FG, MENUBOX_BORDER_BG, MENUBOX_BORDER_HL},
++    {ITEM_FG, ITEM_BG, ITEM_HL},
++    {ITEM_SELECTED_FG, ITEM_SELECTED_BG, ITEM_SELECTED_HL},
++    {TAG_FG, TAG_BG, TAG_HL},
++    {TAG_SELECTED_FG, TAG_SELECTED_BG, TAG_SELECTED_HL},
++    {TAG_KEY_FG, TAG_KEY_BG, TAG_KEY_HL},
++    {TAG_KEY_SELECTED_FG, TAG_KEY_SELECTED_BG, TAG_KEY_SELECTED_HL},
++    {CHECK_FG, CHECK_BG, CHECK_HL},
++    {CHECK_SELECTED_FG, CHECK_SELECTED_BG, CHECK_SELECTED_HL},
++    {UARROW_FG, UARROW_BG, UARROW_HL},
++    {DARROW_FG, DARROW_BG, DARROW_HL},
++};                            /* color_table */
++
++/*
++ * Set window to attribute 'attr'
++ */
++void
++attr_clear (WINDOW * win, int height, int width, chtype attr)
++{
++    int i, j;
++
++    wattrset (win, attr);
++    for (i = 0; i < height; i++) {
++      wmove (win, i, 0);
++      for (j = 0; j < width; j++)
++          waddch (win, ' ');
++    }
++    touchwin (win);
++}
++
++void dialog_clear (void)
++{
++    attr_clear (stdscr, LINES, COLS, screen_attr);
++    /* Display background title if it exists ... - SLH */
++    if (backtitle != NULL) {
++        int i;
++
++        wattrset (stdscr, screen_attr);
++        mvwaddstr (stdscr, 0, 1, (char *)backtitle);
++        wmove (stdscr, 1, 1);
++        for (i = 1; i < COLS - 1; i++)
++            waddch (stdscr, ACS_HLINE);
++    }
++    wnoutrefresh (stdscr);
++}
++
++/*
++ * Do some initialization for dialog
++ */
++void
++init_dialog (void)
++{
++    initscr ();                       /* Init curses */
++    keypad (stdscr, TRUE);
++    cbreak ();
++    noecho ();
++
++
++    if (use_colors)   /* Set up colors */
++      color_setup ();
++
++
++    dialog_clear ();
++}
++
++/*
++ * Setup for color display
++ */
++void
++color_setup (void)
++{
++    int i;
++
++    if (has_colors ()) {      /* Terminal supports color? */
++      start_color ();
++
++      /* Initialize color pairs */
++      for (i = 0; i < ATTRIBUTE_COUNT; i++)
++          init_pair (i + 1, color_table[i][0], color_table[i][1]);
++
++      /* Setup color attributes */
++      for (i = 0; i < ATTRIBUTE_COUNT; i++)
++          attributes[i] = C_ATTR (color_table[i][2], i + 1);
++    }
++}
++
++/*
++ * End using dialog functions.
++ */
++void
++end_dialog (void)
++{
++    endwin ();
++}
++
++
++/*
++ * Print a string of text in a window, automatically wrap around to the
++ * next line if the string is too long to fit on one line. Newline
++ * characters '\n' are replaced by spaces.  We start on a new line
++ * if there is no room for at least 4 nonblanks following a double-space.
++ */
++void
++print_autowrap (WINDOW * win, const char *prompt, int width, int y, int x)
++{
++    int newl, cur_x, cur_y;
++    int i, prompt_len, room, wlen;
++    char tempstr[MAX_LEN + 1], *word, *sp, *sp2;
++
++    strcpy (tempstr, prompt);
++
++    prompt_len = strlen(tempstr);
++      
++    /*
++     * Remove newlines
++     */
++    for(i=0; i<prompt_len; i++) {
++      if(tempstr[i] == '\n') tempstr[i] = ' ';
++    }
++
++    if (prompt_len <= width - x * 2) {        /* If prompt is short */
++      wmove (win, y, (width - prompt_len) / 2);
++      waddstr (win, tempstr);
++    } else {
++      cur_x = x;
++      cur_y = y;
++      newl = 1;
++      word = tempstr;
++      while (word && *word) {
++          sp = index(word, ' ');
++          if (sp)
++              *sp++ = 0;
++
++          /* Wrap to next line if either the word does not fit,
++             or it is the first word of a new sentence, and it is
++             short, and the next word does not fit. */
++          room = width - cur_x;
++          wlen = strlen(word);
++          if (wlen > room ||
++             (newl && wlen < 4 && sp && wlen+1+strlen(sp) > room
++                   && (!(sp2 = index(sp, ' ')) || wlen+1+(sp2-sp) > room))) {
++              cur_y++;
++              cur_x = x;
++          }
++          wmove (win, cur_y, cur_x);
++          waddstr (win, word);
++          getyx (win, cur_y, cur_x);
++          cur_x++;
++          if (sp && *sp == ' ') {
++              cur_x++;        /* double space */
++              while (*++sp == ' ');
++              newl = 1;
++          } else
++              newl = 0;
++          word = sp;
++      }
++    }
++}
++
++/*
++ * Print a button
++ */
++void
++print_button (WINDOW * win, const char *label, int y, int x, int selected)
++{
++    int i, temp;
++
++    wmove (win, y, x);
++    wattrset (win, selected ? button_active_attr : button_inactive_attr);
++    waddstr (win, "<");
++    temp = strspn (label, " ");
++    label += temp;
++    wattrset (win, selected ? button_label_active_attr
++            : button_label_inactive_attr);
++    for (i = 0; i < temp; i++)
++      waddch (win, ' ');
++    wattrset (win, selected ? button_key_active_attr
++            : button_key_inactive_attr);
++    waddch (win, label[0]);
++    wattrset (win, selected ? button_label_active_attr
++            : button_label_inactive_attr);
++    waddstr (win, (char *)label + 1);
++    wattrset (win, selected ? button_active_attr : button_inactive_attr);
++    waddstr (win, ">");
++    wmove (win, y, x + temp + 1);
++}
++
++/*
++ * Draw a rectangular box with line drawing characters
++ */
++void
++draw_box (WINDOW * win, int y, int x, int height, int width,
++        chtype box, chtype border)
++{
++    int i, j;
++
++    wattrset (win, 0);
++    for (i = 0; i < height; i++) {
++      wmove (win, y + i, x);
++      for (j = 0; j < width; j++)
++          if (!i && !j)
++              waddch (win, border | ACS_ULCORNER);
++          else if (i == height - 1 && !j)
++              waddch (win, border | ACS_LLCORNER);
++          else if (!i && j == width - 1)
++              waddch (win, box | ACS_URCORNER);
++          else if (i == height - 1 && j == width - 1)
++              waddch (win, box | ACS_LRCORNER);
++          else if (!i)
++              waddch (win, border | ACS_HLINE);
++          else if (i == height - 1)
++              waddch (win, box | ACS_HLINE);
++          else if (!j)
++              waddch (win, border | ACS_VLINE);
++          else if (j == width - 1)
++              waddch (win, box | ACS_VLINE);
++          else
++              waddch (win, box | ' ');
++    }
++}
++
++/*
++ * Draw shadows along the right and bottom edge to give a more 3D look
++ * to the boxes
++ */
++void
++draw_shadow (WINDOW * win, int y, int x, int height, int width)
++{
++    int i;
++
++    if (has_colors ()) {      /* Whether terminal supports color? */
++      wattrset (win, shadow_attr);
++      wmove (win, y + height, x + 2);
++      for (i = 0; i < width; i++)
++          waddch (win, winch (win) & A_CHARTEXT);
++      for (i = y + 1; i < y + height + 1; i++) {
++          wmove (win, i, x + width);
++          waddch (win, winch (win) & A_CHARTEXT);
++          waddch (win, winch (win) & A_CHARTEXT);
++      }
++      wnoutrefresh (win);
++    }
++}
++
++/*
++ *  Return the position of the first alphabetic character in a string.
++ */
++int
++first_alpha(const char *string, const char *exempt)
++{
++      int i, in_paren=0, c;
++
++      for (i = 0; i < strlen(string); i++) {
++              c = tolower(string[i]);
++
++              if (strchr("<[(", c)) ++in_paren;
++              if (strchr(">])", c) && in_paren > 0) --in_paren;
++
++              if ((! in_paren) && isalpha(c) && 
++                   strchr(exempt, c) == 0)
++                      return i;
++      }
++
++      return 0;
++}
++
++/*
++ * Get the first selected item in the dialog_list_item list.
++ */
++struct dialog_list_item *
++first_sel_item(int item_no, struct dialog_list_item ** items)
++{
++      int i;
++
++      for (i = 0; i < item_no; i++) {
++              if (items[i]->selected)
++                      return items[i];
++      }
++
++      return NULL;
++}
+diff -Nur busybox-1.00/scripts/config/lxdialog/yesno.c busybox/scripts/config/lxdialog/yesno.c
+--- busybox-1.00/scripts/config/lxdialog/yesno.c       1970-01-01 01:00:00.000000000 +0100
++++ busybox/scripts/config/lxdialog/yesno.c    2005-06-04 08:20:02.000000000 +0200
+@@ -0,0 +1,118 @@
++/*
++ *  yesno.c -- implements the yes/no box
++ *
++ *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
++ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
++ *
++ *  This program is free software; you can redistribute it and/or
++ *  modify it under the terms of the GNU General Public License
++ *  as published by the Free Software Foundation; either version 2
++ *  of the License, or (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include "dialog.h"
++
++/*
++ * Display termination buttons
++ */
++static void
++print_buttons(WINDOW *dialog, int height, int width, int selected)
++{
++    int x = width / 2 - 10;
++    int y = height - 2;
++
++    print_button (dialog, " Yes ", y, x, selected == 0);
++    print_button (dialog, "  No  ", y, x + 13, selected == 1);
++
++    wmove(dialog, y, x+1 + 13*selected );
++    wrefresh (dialog);
++}
++
++/*
++ * Display a dialog box with two buttons - Yes and No
++ */
++int
++dialog_yesno (const char *title, const char *prompt, int height, int width)
++{
++    int i, x, y, key = 0, button = 0;
++    WINDOW *dialog;
++
++    /* center dialog box on screen */
++    x = (COLS - width) / 2;
++    y = (LINES - height) / 2;
++
++    draw_shadow (stdscr, y, x, height, width);
++
++    dialog = newwin (height, width, y, x);
++    keypad (dialog, TRUE);
++
++    draw_box (dialog, 0, 0, height, width, dialog_attr, border_attr);
++    wattrset (dialog, border_attr);
++    mvwaddch (dialog, height-3, 0, ACS_LTEE);
++    for (i = 0; i < width - 2; i++)
++      waddch (dialog, ACS_HLINE);
++    wattrset (dialog, dialog_attr);
++    waddch (dialog, ACS_RTEE);
++
++    if (title != NULL && strlen(title) >= width-2 ) {
++      /* truncate long title -- mec */
++      char * title2 = malloc(width-2+1);
++      memcpy( title2, title, width-2 );
++      title2[width-2] = '\0';
++      title = title2;
++    }
++
++    if (title != NULL) {
++      wattrset (dialog, title_attr);
++      mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' ');
++      waddstr (dialog, (char *)title);
++      waddch (dialog, ' ');
++    }
++
++    wattrset (dialog, dialog_attr);
++    print_autowrap (dialog, prompt, width - 2, 1, 3);
++
++    print_buttons(dialog, height, width, 0);
++
++    while (key != ESC) {
++      key = wgetch (dialog);
++      switch (key) {
++      case 'Y':
++      case 'y':
++          delwin (dialog);
++          return 0;
++      case 'N':
++      case 'n':
++          delwin (dialog);
++          return 1;
++
++      case TAB:
++      case KEY_LEFT:
++      case KEY_RIGHT:
++          button = ((key == KEY_LEFT ? --button : ++button) < 0)
++                      ? 1 : (button > 1 ? 0 : button);
++
++          print_buttons(dialog, height, width, button);
++          wrefresh (dialog);
++          break;
++      case ' ':
++      case '\n':
++          delwin (dialog);
++          return button;
++      case ESC:
++          break;
++      }
++    }
++
++    delwin (dialog);
++    return -1;                        /* ESC pressed */
++}
+diff -Nur busybox-1.00/scripts/config/mconf.c busybox/scripts/config/mconf.c
+--- busybox-1.00/scripts/config/mconf.c        2004-10-08 09:58:30.000000000 +0200
++++ busybox/scripts/config/mconf.c     2005-06-04 08:20:03.000000000 +0200
+@@ -23,18 +23,150 @@
+ #include <termios.h>
+ #include <unistd.h>
+-#include "dialog.h"
++#include "lxdialog/dialog.h"
+ #define LKC_DIRECT_LINK
+ #include "lkc.h"
+ static char menu_backtitle[128];
+-static const char menu_instructions[] =
++static const char mconf_readme[] =
++"Overview\n"
++"--------\n"
++"Some features may be built directly into BusyBox.  Some features\n"
++"may be completely removed altogether.  There are also certain\n"
++"parameters which are not really features, but must be\n"
++"entered in as decimal or hexadecimal numbers or possibly text.\n"
++"\n"
++"Menu items beginning with [*] or [ ] represent features\n"
++"configured to be built in or removed respectively.\n"
++"\n"
++"To change any of these features, highlight it with the cursor\n"
++"keys and press <Y> to build it in or <N> to removed it.\n"
++"You may also press the <Space Bar> to cycle\n"
++"through the available options (ie. Y->N->Y).\n"
++"\n"
++"Some additional keyboard hints:\n"
++"\n"
++"Menus\n"
++"----------\n"
++"o  Use the Up/Down arrow keys (cursor keys) to highlight the item\n"
++"   you wish to change or submenu wish to select and press <Enter>.\n"
++"   Submenus are designated by \"--->\".\n"
++"\n"
++"   Shortcut: Press the option's highlighted letter (hotkey).\n"
++"             Pressing a hotkey more than once will sequence\n"
++"             through all visible items which use that hotkey.\n"
++"\n"
++"   You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n"
++"   unseen options into view.\n"
++"\n"
++"o  To exit a menu use the cursor keys to highlight the <Exit> button\n"
++"   and press <ENTER>.\n"
++"\n"
++"   Shortcut: Press <ESC><ESC> or <E> or <X> if there is no hotkey\n"
++"             using those letters.  You may press a single <ESC>, but\n"
++"             there is a delayed response which you may find annoying.\n"
++"\n"
++"   Also, the <TAB> and cursor keys will cycle between <Select>,\n"
++"   <Exit> and <Help>\n"
++"\n"
++"o  To get help with an item, use the cursor keys to highlight <Help>\n"
++"   and Press <ENTER>.\n"
++"\n"
++"   Shortcut: Press <H> or <?>.\n"
++"\n"
++"\n"
++"Radiolists  (Choice lists)\n"
++"-----------\n"
++"o  Use the cursor keys to select the option you wish to set and press\n"
++"   <S> or the <SPACE BAR>.\n"
++"\n"
++"   Shortcut: Press the first letter of the option you wish to set then\n"
++"             press <S> or <SPACE BAR>.\n"
++"\n"
++"o  To see available help for the item, use the cursor keys to highlight\n"
++"   <Help> and Press <ENTER>.\n"
++"\n"
++"   Shortcut: Press <H> or <?>.\n"
++"\n"
++"   Also, the <TAB> and cursor keys will cycle between <Select> and\n"
++"   <Help>\n"
++"\n"
++"\n"
++"Data Entry\n"
++"-----------\n"
++"o  Enter the requested information and press <ENTER>\n"
++"   If you are entering hexadecimal values, it is not necessary to\n"
++"   add the '0x' prefix to the entry.\n"
++"\n"
++"o  For help, use the <TAB> or cursor keys to highlight the help option\n"
++"   and press <ENTER>.  You can try <TAB><H> as well.\n"
++"\n"
++"\n"
++"Text Box    (Help Window)\n"
++"--------\n"
++"o  Use the cursor keys to scroll up/down/left/right.  The VI editor\n"
++"   keys h,j,k,l function here as do <SPACE BAR> and <B> for those\n"
++"   who are familiar with less and lynx.\n"
++"\n"
++"o  Press <E>, <X>, <Enter> or <Esc><Esc> to exit.\n"
++"\n"
++"\n"
++"Alternate Configuration Files\n"
++"-----------------------------\n"
++"Menuconfig supports the use of alternate configuration files for\n"
++"those who, for various reasons, find it necessary to switch\n"
++"between different configurations.\n"
++"\n"
++"At the end of the main menu you will find two options.  One is\n"
++"for saving the current configuration to a file of your choosing.\n"
++"The other option is for loading a previously saved alternate\n"
++"configuration.\n"
++"\n"
++"Even if you don't use alternate configuration files, but you\n"
++"find during a Menuconfig session that you have completely messed\n"
++"up your settings, you may use the \"Load Alternate...\" option to\n"
++"restore your previously saved settings from \".config\" without\n"
++"restarting Menuconfig.\n"
++"\n"
++"Other information\n"
++"-----------------\n"
++"If you use Menuconfig in an XTERM window make sure you have your\n"
++"$TERM variable set to point to a xterm definition which supports color.\n"
++"Otherwise, Menuconfig will look rather bad.  Menuconfig will not\n"
++"display correctly in a RXVT window because rxvt displays only one\n"
++"intensity of color, bright.\n"
++"\n"
++"Menuconfig will display larger menus on screens or xterms which are\n"
++"set to display more than the standard 25 row by 80 column geometry.\n"
++"In order for this to work, the \"stty size\" command must be able to\n"
++"display the screen's current row and column geometry.  I STRONGLY\n"
++"RECOMMEND that you make sure you do NOT have the shell variables\n"
++"LINES and COLUMNS exported into your environment.  Some distributions\n"
++"export those variables via /etc/profile.  Some ncurses programs can\n"
++"become confused when those variables (LINES & COLUMNS) don't reflect\n"
++"the true screen size.\n"
++"\n"
++"Optional personality available\n"
++"------------------------------\n"
++"If you prefer to have all of the options listed in a single\n"
++"menu, rather than the default multimenu hierarchy, run the menuconfig\n"
++"with MENUCONFIG_MODE environment variable set to single_menu. Example:\n"
++"\n"
++"make MENUCONFIG_MODE=single_menu menuconfig\n"
++"\n"
++"<Enter> will then unroll the appropriate category, or enfold it if it\n"
++"is already unrolled.\n"
++"\n"
++"Note that this mode can eventually be a little more CPU expensive\n"
++"(especially with a larger number of unrolled categories) than the\n"
++"default mode.\n",
++menu_instructions[] =
+       "Arrow keys navigate the menu.  "
+       "<Enter> selects submenus --->.  "
+       "Highlighted letters are hotkeys.  "
+       "Pressing <Y> selectes a feature, while <N> will exclude a feature.  "
+-      "Press <Esc><Esc> to exit, <?> for Help.  "
++      "Press <Esc><Esc> to exit, <?> for Help, </> for Search.  "
+       "Legend: [*] feature is selected  [ ] feature is excluded",
+ radiolist_instructions[] =
+       "Use the arrow keys to navigate this window or "
+@@ -85,23 +217,50 @@
+       "\n"
+       "If you are uncertain what all this means then you should probably\n"
+       "leave this blank.\n",
+-top_menu_help[] =
++search_help[] =
+       "\n"
+-      "Use the Up/Down arrow keys (cursor keys) to highlight the item\n"
+-      "you wish to change or submenu wish to select and press <Enter>.\n"
+-      "Submenus are designated by \"--->\".\n"
++      "Search for CONFIG_ symbols and display their relations.\n"
++      "Example: search for \"^FOO\"\n"
++      "Result:\n"
++      "-----------------------------------------------------------------\n"
++      "Symbol: FOO [=m]\n"
++      "Prompt: Foo bus is used to drive the bar HW\n"
++      "Defined at drivers/pci/Kconfig:47\n"
++      "Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
++      "Location:\n"
++      "  -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n"
++      "    -> PCI support (PCI [=y])\n"
++      "      -> PCI access mode (<choice> [=y])\n"
++      "Selects: LIBCRC32\n"
++      "Selected by: BAR\n"
++      "-----------------------------------------------------------------\n"
++      "o The line 'Prompt:' shows the text used in the menu structure for\n"
++      "  this CONFIG_ symbol\n"
++      "o The 'Defined at' line tell at what file / line number the symbol\n"
++      "  is defined\n"
++      "o The 'Depends on:' line tell what symbols needs to be defined for\n"
++      "  this symbol to be visible in the menu (selectable)\n"
++      "o The 'Location:' lines tell where in the menu structure this symbol\n"
++      "  is located\n"
++      "    A location followed by a [=y] indicate that this is a selectable\n"
++      "    menu item - and current value is displayed inside brackets.\n"
++      "o The 'Selects:' line tell what symbol will be automatically\n"
++      "  selected if this symbol is selected (y or m)\n"
++      "o The 'Selected by' line tell what symbol has selected this symbol\n"
+       "\n"
+-      "Shortcut: Press the option's highlighted letter (hotkey).\n"
+-      "\n"
+-      "You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n"
+-      "unseen options into view.\n"
+-;
++      "Only relevant lines are shown.\n"
++      "\n\n"
++      "Search examples:\n"
++      "Examples: USB  => find all CONFIG_ symbols containing USB\n"
++      "          ^USB => find all CONFIG_ symbols starting with USB\n"
++      "          USB$ => find all CONFIG_ symbols ending with USB\n"
++      "\n";
+ static char filename[PATH_MAX+1] = ".config";
+-static int indent = 0;
++static int indent;
+ static struct termios ios_org;
+-static int rows, cols;
+-struct menu *current_menu;
++static int rows = 0, cols = 0;
++static struct menu *current_menu;
+ static int child_count;
+ static int single_menu_mode;
+@@ -116,33 +275,31 @@
+ static void show_textbox(const char *title, const char *text, int r, int c);
+ static void show_helptext(const char *title, const char *text);
+ static void show_help(struct menu *menu);
+-static void show_readme(void);
++static void show_file(const char *filename, const char *title, int r, int c);
+ static void init_wsize(void)
+ {
+       struct winsize ws;
+       char *env;
+-      if (ioctl(1, TIOCGWINSZ, &ws) == -1) {
+-              rows = 24;
+-              cols = 80;
+-      } else {
++      if (!ioctl(STDIN_FILENO, TIOCGWINSZ, &ws)) {
+               rows = ws.ws_row;
+               cols = ws.ws_col;
+-              if (!rows) {
+-                      env = getenv("LINES");
+-                      if (env)
+-                              rows = atoi(env);
+-                      if (!rows)
+-                              rows = 24;
+-              }
+-              if (!cols) {
+-                      env = getenv("COLUMNS");
+-                      if (env)
+-                              cols = atoi(env);
+-                      if (!cols)
+-                              cols = 80;
+-              }
++      }
++
++      if (!rows) {
++              env = getenv("LINES");
++              if (env)
++                      rows = atoi(env);
++              if (!rows)
++                      rows = 24;
++      }
++      if (!cols) {
++              env = getenv("COLUMNS");
++              if (env)
++                      cols = atoi(env);
++              if (!cols)
++                      cols = 80;
+       }
+       if (rows < 19 || cols < 80) {
+@@ -214,6 +371,103 @@
+       item_no = 0;
+ }
++static void get_prompt_str(struct gstr *r, struct property *prop)
++{
++      int i, j;
++      struct menu *submenu[8], *menu;
++
++      str_printf(r, "Prompt: %s\n", prop->text);
++      str_printf(r, "  Defined at %s:%d\n", prop->menu->file->name,
++              prop->menu->lineno);
++      if (!expr_is_yes(prop->visible.expr)) {
++              str_append(r, "  Depends on: ");
++              expr_gstr_print(prop->visible.expr, r);
++              str_append(r, "\n");
++      }
++      menu = prop->menu->parent;
++      for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent)
++              submenu[i++] = menu;
++      if (i > 0) {
++              str_printf(r, "  Location:\n");
++              for (j = 4; --i >= 0; j += 2) {
++                      menu = submenu[i];
++                      str_printf(r, "%*c-> %s", j, ' ', menu_get_prompt(menu));
++                      if (menu->sym) {
++                              str_printf(r, " (%s [=%s])", menu->sym->name ?
++                                      menu->sym->name : "<choice>",
++                                      sym_get_string_value(menu->sym));
++                      }
++                      str_append(r, "\n");
++              }
++      }
++}
++
++static void get_symbol_str(struct gstr *r, struct symbol *sym)
++{
++      bool hit;
++      struct property *prop;
++
++      str_printf(r, "Symbol: %s [=%s]\n", sym->name,
++                                     sym_get_string_value(sym));
++      for_all_prompts(sym, prop)
++              get_prompt_str(r, prop);
++      hit = false;
++      for_all_properties(sym, prop, P_SELECT) {
++              if (!hit) {
++                      str_append(r, "  Selects: ");
++                      hit = true;
++              } else
++                      str_printf(r, " && ");
++              expr_gstr_print(prop->expr, r);
++      }
++      if (hit)
++              str_append(r, "\n");
++      if (sym->rev_dep.expr) {
++              str_append(r, "  Selected by: ");
++              expr_gstr_print(sym->rev_dep.expr, r);
++              str_append(r, "\n");
++      }
++      str_append(r, "\n\n");
++}
++
++static struct gstr get_relations_str(struct symbol **sym_arr)
++{
++      struct symbol *sym;
++      struct gstr res = str_new();
++      int i;
++
++      for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
++              get_symbol_str(&res, sym);
++      if (!i)
++              str_append(&res, "No matches found.\n");
++      return res;
++}
++
++static void search_conf(void)
++{
++      struct symbol **sym_arr;
++      struct gstr res;
++
++again:
++      switch (dialog_inputbox("Search Configuration Parameter",
++                              "Enter Keyword", 10, 75,
++                              NULL)) {
++      case 0:
++              break;
++      case 1:
++              show_helptext("Search Configuration", search_help);
++              goto again;
++      default:
++              return;
++      }
++
++      sym_arr = sym_re_search(dialog_input_result);
++      res = get_relations_str(sym_arr);
++      free(sym_arr);
++      show_textbox("Search Results", str_get(&res), 0, 0);
++      str_free(&res);
++}
++
+ static void build_conf(struct menu *menu)
+ {
+       struct symbol *sym;
+@@ -308,6 +562,11 @@
+                       return;
+               }
+       } else {
++              if (menu == current_menu) {
++                      cprint_tag(":%p", menu);
++                      cprint_name("---%*c%s", indent + 1, ' ', menu_get_prompt(menu));
++                      goto conf_childs;
++              }
+               child_count++;
+               val = sym_get_tristate_value(sym);
+               if (sym_is_choice_value(sym) && val == yes) {
+@@ -376,7 +635,7 @@
+       while (1) {
+               indent = 0;
+               child_count = 0;
+-              current_menu = menu;
++              current_menu = menu;
+               cdone(); cinit();
+               build_conf(menu);
+               if (!child_count)
+@@ -441,7 +700,7 @@
+                       if (sym)
+                               show_help(submenu);
+                       else
+-                              show_readme();
++                              show_helptext("README", mconf_readme);
+                       break;
+               case 3:
+                       if (type == 't') {
+@@ -465,6 +724,9 @@
+                       else if (type == 'm')
+                               conf(submenu);
+                       break;
++              case 7:
++                      search_conf();
++                      break;
+               }
+       }
+ }
+@@ -476,37 +738,39 @@
+       fd = creat(".help.tmp", 0777);
+       write(fd, text, strlen(text));
+       close(fd);
+-      while (dialog_textbox(title, ".help.tmp", r, c) < 0)
+-              ;
++      show_file(".help.tmp", title, r, c);
+       unlink(".help.tmp");
+ }
+ static void show_helptext(const char *title, const char *text)
+ {
+-      show_textbox(title, text, rows, cols);
++      show_textbox(title, text, 0, 0);
+ }
+ static void show_help(struct menu *menu)
+ {
+-      const char *help;
+-      char *helptext;
++      struct gstr help = str_new();
+       struct symbol *sym = menu->sym;
+-      help = sym->help;
+-      if (!help)
+-              help = nohelp_text;
+-      if (sym->name) {
+-              helptext = malloc(strlen(sym->name) + strlen(help) + 16);
+-              sprintf(helptext, "%s:\n\n%s", sym->name, help);
+-              show_helptext(menu_get_prompt(menu), helptext);
+-              free(helptext);
+-      } else
+-              show_helptext(menu_get_prompt(menu), help);
++      if (sym->help)
++      {
++              if (sym->name) {
++                      str_printf(&help, "%s:\n\n", sym->name);
++                      str_append(&help, sym->help);
++                      str_append(&help, "\n");
++              }
++      } else {
++              str_append(&help, nohelp_text);
++      }
++      get_symbol_str(&help, sym);
++      show_helptext(menu_get_prompt(menu), str_get(&help));
++      str_free(&help);
+ }
+-static void show_readme(void)
++static void show_file(const char *filename, const char *title, int r, int c)
+ {
+-      show_helptext("Help", top_menu_help);
++      while (dialog_textbox(title, filename, r ? r : rows, c ? c : cols) < 0)
++              ;
+ }
+ static void conf_choice(struct menu *menu)
+@@ -667,9 +931,9 @@
+ int main(int ac, char **av)
+ {
+-      int stat;
+-      char *mode;
+       struct symbol *sym;
++      char *mode;
++      int stat;
+       conf_parse(av[1]);
+       conf_read(NULL);
+@@ -697,7 +961,7 @@
+       init_dialog();
+       do {
+               stat = dialog_yesno(NULL,
+-                              "Do you wish to save your new BusyBox configuration?", 5, 60);
++                                  "Do you wish to save your new BusyBox configuration?", 5, 60);
+       } while (stat < 0);
+       end_dialog();
+diff -Nur busybox-1.00/scripts/config/menu.c busybox/scripts/config/menu.c
+--- busybox-1.00/scripts/config/menu.c 2004-07-15 08:01:05.000000000 +0200
++++ busybox/scripts/config/menu.c      2005-06-04 08:20:03.000000000 +0200
+@@ -10,7 +10,6 @@
+ #include "lkc.h"
+ struct menu rootmenu;
+-struct menu *current_menu, *current_entry;
+ static struct menu **last_entry_ptr;
+ struct file *file_list;
+@@ -389,43 +388,3 @@
+       return menu;
+ }
+-struct file *file_lookup(const char *name)
+-{
+-      struct file *file;
+-
+-      for (file = file_list; file; file = file->next) {
+-              if (!strcmp(name, file->name))
+-                      return file;
+-      }
+-
+-      file = malloc(sizeof(*file));
+-      memset(file, 0, sizeof(*file));
+-      file->name = strdup(name);
+-      file->next = file_list;
+-      file_list = file;
+-      return file;
+-}
+-
+-int file_write_dep(const char *name)
+-{
+-      struct file *file;
+-      FILE *out;
+-
+-      if (!name)
+-              name = ".config.cmd";
+-      out = fopen(".config.tmp", "w");
+-      if (!out)
+-              return 1;
+-      fprintf(out, "deps_config := \\\n");
+-      for (file = file_list; file; file = file->next) {
+-              if (file->next)
+-                      fprintf(out, "\t%s \\\n", file->name);
+-              else
+-                      fprintf(out, "\t%s\n", file->name);
+-      }
+-      fprintf(out, "\n.config include/config.h: $(deps_config)\n\n$(deps_config):\n");
+-      fclose(out);
+-      rename(".config.tmp", name);
+-      return 0;
+-}
+-
+diff -Nur busybox-1.00/scripts/config/menubox.c busybox/scripts/config/menubox.c
+--- busybox-1.00/scripts/config/menubox.c      2004-03-15 09:29:08.000000000 +0100
++++ busybox/scripts/config/menubox.c   1970-01-01 01:00:00.000000000 +0100
+@@ -1,436 +0,0 @@
+-/*
+- *  menubox.c -- implements the menu box
+- *
+- *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+- *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw@cfw.com)
+- *
+- *  This program is free software; you can redistribute it and/or
+- *  modify it under the terms of the GNU General Public License
+- *  as published by the Free Software Foundation; either version 2
+- *  of the License, or (at your option) any later version.
+- *
+- *  This program is distributed in the hope that it will be useful,
+- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- *  GNU General Public License for more details.
+- *
+- *  You should have received a copy of the GNU General Public License
+- *  along with this program; if not, write to the Free Software
+- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+- */
+-
+-/*
+- *  Changes by Clifford Wolf (god@clifford.at)
+- *
+- *  [ 1998-06-13 ]
+- *
+- *    *)  A bugfix for the Page-Down problem
+- *
+- *    *)  Formerly when I used Page Down and Page Up, the cursor would be set
+- *        to the first position in the menu box.  Now lxdialog is a bit
+- *        smarter and works more like other menu systems (just have a look at
+- *        it).
+- *
+- *    *)  Formerly if I selected something my scrolling would be broken because
+- *        lxdialog is re-invoked by the Menuconfig shell script, can't
+- *        remember the last scrolling position, and just sets it so that the
+- *        cursor is at the bottom of the box.  Now it writes the temporary file
+- *        lxdialog.scrltmp which contains this information. The file is
+- *        deleted by lxdialog if the user leaves a submenu or enters a new
+- *        one, but it would be nice if Menuconfig could make another "rm -f"
+- *        just to be sure.  Just try it out - you will recognise a difference!
+- *
+- *  [ 1998-06-14 ]
+- *
+- *    *)  Now lxdialog is crash-safe against broken "lxdialog.scrltmp" files
+- *        and menus change their size on the fly.
+- *
+- *    *)  If for some reason the last scrolling position is not saved by
+- *        lxdialog, it sets the scrolling so that the selected item is in the
+- *        middle of the menu box, not at the bottom.
+- *
+- * 02 January 1999, Michael Elizabeth Chastain (mec@shout.net)
+- * Reset 'scroll' to 0 if the value from lxdialog.scrltmp is bogus.
+- * This fixes a bug in Menuconfig where using ' ' to descend into menus
+- * would leave mis-synchronized lxdialog.scrltmp files lying around,
+- * fscanf would read in 'scroll', and eventually that value would get used.
+- */
+-
+-#include "dialog.h"
+-
+-static int menu_width, item_x;
+-
+-/*
+- * Print menu item
+- */
+-static void
+-print_item (WINDOW * win, const char *item, int choice, int selected, int hotkey)
+-{
+-    int j;
+-    char menu_item[menu_width+1];
+-
+-    strncpy(menu_item, item, menu_width);
+-    menu_item[menu_width] = 0;
+-    j = first_alpha(menu_item, "YyNnMm");
+-
+-    /* Clear 'residue' of last item */
+-    wattrset (win, menubox_attr);
+-    wmove (win, choice, 0);
+-#if OLD_NCURSES
+-    {
+-        int i;
+-        for (i = 0; i < menu_width; i++)
+-          waddch (win, ' ');
+-    }
+-#else
+-    wclrtoeol(win);
+-#endif
+-    wattrset (win, selected ? item_selected_attr : item_attr);
+-    mvwaddstr (win, choice, item_x, menu_item);
+-    if (hotkey) {
+-      wattrset (win, selected ? tag_key_selected_attr : tag_key_attr);
+-      mvwaddch(win, choice, item_x+j, menu_item[j]);
+-    }
+-    if (selected) {
+-      wmove (win, choice, item_x+1);
+-      wrefresh (win);
+-    }
+-}
+-
+-/*
+- * Print the scroll indicators.
+- */
+-static void
+-print_arrows (WINDOW * win, int item_no, int scroll,
+-              int y, int x, int height)
+-{
+-    int cur_y, cur_x;
+-
+-    getyx(win, cur_y, cur_x);
+-
+-    wmove(win, y, x);
+-
+-    if (scroll > 0) {
+-      wattrset (win, uarrow_attr);
+-      waddch (win, ACS_UARROW);
+-      waddstr (win, "(-)");
+-    }
+-    else {
+-      wattrset (win, menubox_attr);
+-      waddch (win, ACS_HLINE);
+-      waddch (win, ACS_HLINE);
+-      waddch (win, ACS_HLINE);
+-      waddch (win, ACS_HLINE);
+-    }
+-
+-   y = y + height + 1;
+-   wmove(win, y, x);
+-
+-   if ((height < item_no) && (scroll + height < item_no)) {
+-      wattrset (win, darrow_attr);
+-      waddch (win, ACS_DARROW);
+-      waddstr (win, "(+)");
+-    }
+-    else {
+-      wattrset (win, menubox_border_attr);
+-      waddch (win, ACS_HLINE);
+-      waddch (win, ACS_HLINE);
+-      waddch (win, ACS_HLINE);
+-      waddch (win, ACS_HLINE);
+-   }
+-
+-   wmove(win, cur_y, cur_x);
+-}
+-
+-/*
+- * Display the termination buttons.
+- */
+-static void
+-print_buttons (WINDOW *win, int height, int width, int selected)
+-{
+-    int x = width / 2 - 16;
+-    int y = height - 2;
+-
+-    print_button (win, "Select", y, x, selected == 0);
+-    print_button (win, " Exit ", y, x + 12, selected == 1);
+-    print_button (win, " Help ", y, x + 24, selected == 2);
+-
+-    wmove(win, y, x+1+12*selected);
+-    wrefresh (win);
+-}
+-
+-/*
+- * Display a menu for choosing among a number of options
+- */
+-int
+-dialog_menu (const char *title, const char *prompt, int height, int width,
+-              int menu_height, const char *current, int item_no,
+-              struct dialog_list_item ** items)
+-{
+-    int i, j, x, y, box_x, box_y;
+-    int key = 0, button = 0, scroll = 0, choice = 0, first_item = 0, max_choice;
+-    WINDOW *dialog, *menu;
+-    FILE *f;
+-
+-    max_choice = MIN (menu_height, item_no);
+-
+-    /* center dialog box on screen */
+-    x = (COLS - width) / 2;
+-    y = (LINES - height) / 2;
+-
+-    draw_shadow (stdscr, y, x, height, width);
+-
+-    dialog = newwin (height, width, y, x);
+-    keypad (dialog, TRUE);
+-
+-    draw_box (dialog, 0, 0, height, width, dialog_attr, border_attr);
+-    wattrset (dialog, border_attr);
+-    mvwaddch (dialog, height - 3, 0, ACS_LTEE);
+-    for (i = 0; i < width - 2; i++)
+-      waddch (dialog, ACS_HLINE);
+-    wattrset (dialog, dialog_attr);
+-    wbkgdset (dialog, dialog_attr & A_COLOR);
+-    waddch (dialog, ACS_RTEE);
+-
+-    if (title != NULL && strlen(title) >= width-2 ) {
+-      /* truncate long title -- mec */
+-      char * title2 = malloc(width-2+1);
+-      memcpy( title2, title, width-2 );
+-      title2[width-2] = '\0';
+-      title = title2;
+-    }
+-
+-    if (title != NULL) {
+-      wattrset (dialog, title_attr);
+-      mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' ');
+-      waddstr (dialog, (char *)title);
+-      waddch (dialog, ' ');
+-    }
+-
+-    wattrset (dialog, dialog_attr);
+-    print_autowrap (dialog, prompt, width - 2, 1, 3);
+-
+-    menu_width = width - 6;
+-    box_y = height - menu_height - 5;
+-    box_x = (width - menu_width) / 2 - 1;
+-
+-    /* create new window for the menu */
+-    menu = subwin (dialog, menu_height, menu_width,
+-              y + box_y + 1, x + box_x + 1);
+-    keypad (menu, TRUE);
+-
+-    /* draw a box around the menu items */
+-    draw_box (dialog, box_y, box_x, menu_height + 2, menu_width + 2,
+-            menubox_border_attr, menubox_attr);
+-
+-    /*
+-     * Find length of longest item in order to center menu.
+-     * Set 'choice' to default item.
+-     */
+-    item_x = 0;
+-    for (i = 0; i < item_no; i++) {
+-      item_x = MAX (item_x, MIN(menu_width, strlen (items[i]->name) + 2));
+-      if (strcmp(current, items[i]->tag) == 0) choice = i;
+-    }
+-
+-    item_x = (menu_width - item_x) / 2;
+-
+-    /* get the scroll info from the temp file */
+-    if ( (f=fopen("lxdialog.scrltmp","r")) != NULL ) {
+-      if ( (fscanf(f,"%d\n",&scroll) == 1) && (scroll <= choice) &&
+-           (scroll+max_choice > choice) && (scroll >= 0) &&
+-           (scroll+max_choice <= item_no) ) {
+-          first_item = scroll;
+-          choice = choice - scroll;
+-          fclose(f);
+-      } else {
+-          scroll=0;
+-          remove("lxdialog.scrltmp");
+-          fclose(f);
+-          f=NULL;
+-      }
+-    }
+-    if ( (choice >= max_choice) || (f==NULL && choice >= max_choice/2) ) {
+-      if (choice >= item_no-max_choice/2)
+-          scroll = first_item = item_no-max_choice;
+-      else
+-          scroll = first_item = choice - max_choice/2;
+-      choice = choice - scroll;
+-    }
+-
+-    /* Print the menu */
+-    for (i=0; i < max_choice; i++) {
+-      print_item (menu, items[first_item + i]->name, i, i == choice,
+-                    (items[first_item + i]->tag[0] != ':'));
+-    }
+-
+-    wnoutrefresh (menu);
+-
+-    print_arrows(dialog, item_no, scroll,
+-               box_y, box_x+item_x+1, menu_height);
+-
+-    print_buttons (dialog, height, width, 0);
+-    wmove (menu, choice, item_x+1);
+-    wrefresh (menu);
+-
+-    while (key != ESC) {
+-      key = wgetch(menu);
+-
+-      if (key < 256 && isalpha(key)) key = tolower(key);
+-
+-      if (strchr("ynm", key))
+-              i = max_choice;
+-      else {
+-        for (i = choice+1; i < max_choice; i++) {
+-              j = first_alpha(items[scroll + i]->name, "YyNnMm>");
+-              if (key == tolower(items[scroll + i]->name[j]))
+-                      break;
+-      }
+-      if (i == max_choice)
+-                      for (i = 0; i < max_choice; i++) {
+-                      j = first_alpha(items[scroll + i]->name, "YyNnMm>");
+-                      if (key == tolower(items[scroll + i]->name[j]))
+-                              break;
+-              }
+-      }
+-
+-      if (i < max_choice ||
+-            key == KEY_UP || key == KEY_DOWN ||
+-            key == '-' || key == '+' ||
+-            key == KEY_PPAGE || key == KEY_NPAGE) {
+-
+-            print_item (menu, items[scroll + choice]->name, choice, FALSE,
+-                       (items[scroll + choice]->tag[0] != ':'));
+-
+-          if (key == KEY_UP || key == '-') {
+-                if (choice < 2 && scroll) {
+-                  /* Scroll menu down */
+-                    scrollok (menu, TRUE);
+-                    wscrl (menu, -1);
+-                    scrollok (menu, FALSE);
+-
+-                    scroll--;
+-
+-                    print_item (menu, items[scroll]->name, 0, FALSE,
+-                               (items[scroll]->tag[0] != ':'));
+-              } else
+-                  choice = MAX(choice - 1, 0);
+-
+-          } else if (key == KEY_DOWN || key == '+')  {
+-
+-              print_item (menu, items[scroll + choice]->name, choice, FALSE,
+-                                (items[scroll + choice]->tag[0] != ':'));
+-
+-                if ((choice > max_choice-3) &&
+-                    (scroll + max_choice < item_no)
+-                   ) {
+-                  /* Scroll menu up */
+-                  scrollok (menu, TRUE);
+-                    scroll (menu);
+-                    scrollok (menu, FALSE);
+-
+-                    scroll++;
+-
+-                    print_item (menu, items[scroll + max_choice - 1]->name,
+-                               max_choice-1, FALSE,
+-                               (items[scroll + max_choice - 1]->tag[0] != ':'));
+-                } else
+-                    choice = MIN(choice+1, max_choice-1);
+-
+-          } else if (key == KEY_PPAGE) {
+-              scrollok (menu, TRUE);
+-                for (i=0; (i < max_choice); i++) {
+-                    if (scroll > 0) {
+-                      wscrl (menu, -1);
+-                      scroll--;
+-                      print_item (menu, items[scroll]->name, 0, FALSE,
+-                      (items[scroll]->tag[0] != ':'));
+-                    } else {
+-                        if (choice > 0)
+-                            choice--;
+-                    }
+-                }
+-                scrollok (menu, FALSE);
+-
+-            } else if (key == KEY_NPAGE) {
+-                for (i=0; (i < max_choice); i++) {
+-                    if (scroll+max_choice < item_no) {
+-                      scrollok (menu, TRUE);
+-                      scroll(menu);
+-                      scrollok (menu, FALSE);
+-                      scroll++;
+-                      print_item (menu, items[scroll + max_choice - 1]->name,
+-                                  max_choice-1, FALSE,
+-                                  (items[scroll + max_choice - 1]->tag[0] != ':'));
+-                  } else {
+-                      if (choice+1 < max_choice)
+-                          choice++;
+-                  }
+-                }
+-
+-            } else
+-                choice = i;
+-
+-            print_item (menu, items[scroll + choice]->name, choice, TRUE,
+-                       (items[scroll + choice]->tag[0] != ':'));
+-
+-            print_arrows(dialog, item_no, scroll,
+-                         box_y, box_x+item_x+1, menu_height);
+-
+-            wnoutrefresh (dialog);
+-            wrefresh (menu);
+-
+-          continue;           /* wait for another key press */
+-        }
+-
+-      switch (key) {
+-      case KEY_LEFT:
+-      case TAB:
+-      case KEY_RIGHT:
+-          button = ((key == KEY_LEFT ? --button : ++button) < 0)
+-                      ? 2 : (button > 2 ? 0 : button);
+-
+-          print_buttons(dialog, height, width, button);
+-          wrefresh (menu);
+-          break;
+-      case ' ':
+-      case 's':
+-      case 'y':
+-      case 'n':
+-      case 'm':
+-          /* save scroll info */
+-          if ( (f=fopen("lxdialog.scrltmp","w")) != NULL ) {
+-              fprintf(f,"%d\n",scroll);
+-              fclose(f);
+-          }
+-          delwin (dialog);
+-            items[scroll + choice]->selected = 1;
+-            switch (key) {
+-            case 's': return 3;
+-            case 'y': return 3;
+-            case 'n': return 4;
+-            case 'm': return 5;
+-            case ' ': return 6;
+-            }
+-          return 0;
+-      case 'h':
+-      case '?':
+-          button = 2;
+-      case '\n':
+-          delwin (dialog);
+-          items[scroll + choice]->selected = 1;
+-
+-          remove("lxdialog.scrltmp");
+-          return button;
+-      case 'e':
+-      case 'x':
+-          key = ESC;
+-      case ESC:
+-          break;
+-      }
+-    }
+-
+-    delwin (dialog);
+-    remove("lxdialog.scrltmp");
+-    return -1;                        /* ESC pressed */
+-}
+diff -Nur busybox-1.00/scripts/config/msgbox.c busybox/scripts/config/msgbox.c
+--- busybox-1.00/scripts/config/msgbox.c       2002-12-05 09:41:07.000000000 +0100
++++ busybox/scripts/config/msgbox.c    1970-01-01 01:00:00.000000000 +0100
+@@ -1,85 +0,0 @@
+-/*
+- *  msgbox.c -- implements the message box and info box
+- *
+- *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+- *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw@cfw.com)
+- *
+- *  This program is free software; you can redistribute it and/or
+- *  modify it under the terms of the GNU General Public License
+- *  as published by the Free Software Foundation; either version 2
+- *  of the License, or (at your option) any later version.
+- *
+- *  This program is distributed in the hope that it will be useful,
+- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- *  GNU General Public License for more details.
+- *
+- *  You should have received a copy of the GNU General Public License
+- *  along with this program; if not, write to the Free Software
+- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+- */
+-
+-#include "dialog.h"
+-
+-/*
+- * Display a message box. Program will pause and display an "OK" button
+- * if the parameter 'pause' is non-zero.
+- */
+-int
+-dialog_msgbox (const char *title, const char *prompt, int height, int width,
+-              int pause)
+-{
+-    int i, x, y, key = 0;
+-    WINDOW *dialog;
+-
+-    /* center dialog box on screen */
+-    x = (COLS - width) / 2;
+-    y = (LINES - height) / 2;
+-
+-    draw_shadow (stdscr, y, x, height, width);
+-
+-    dialog = newwin (height, width, y, x);
+-    keypad (dialog, TRUE);
+-
+-    draw_box (dialog, 0, 0, height, width, dialog_attr, border_attr);
+-
+-    if (title != NULL && strlen(title) >= width-2 ) {
+-      /* truncate long title -- mec */
+-      char * title2 = malloc(width-2+1);
+-      memcpy( title2, title, width-2 );
+-      title2[width-2] = '\0';
+-      title = title2;
+-    }
+-
+-    if (title != NULL) {
+-      wattrset (dialog, title_attr);
+-      mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' ');
+-      waddstr (dialog, (char *)title);
+-      waddch (dialog, ' ');
+-    }
+-    wattrset (dialog, dialog_attr);
+-    print_autowrap (dialog, prompt, width - 2, 1, 2);
+-
+-    if (pause) {
+-      wattrset (dialog, border_attr);
+-      mvwaddch (dialog, height - 3, 0, ACS_LTEE);
+-      for (i = 0; i < width - 2; i++)
+-          waddch (dialog, ACS_HLINE);
+-      wattrset (dialog, dialog_attr);
+-      waddch (dialog, ACS_RTEE);
+-
+-      print_button (dialog, "  Ok  ",
+-                    height - 2, width / 2 - 4, TRUE);
+-
+-      wrefresh (dialog);
+-      while (key != ESC && key != '\n' && key != ' ' &&
+-               key != 'O' && key != 'o' && key != 'X' && key != 'x')
+-          key = wgetch (dialog);
+-    } else {
+-      key = '\n';
+-      wrefresh (dialog);
+-    }
+-
+-    delwin (dialog);
+-    return key == ESC ? -1 : 0;
+-}
+diff -Nur busybox-1.00/scripts/config/symbol.c busybox/scripts/config/symbol.c
+--- busybox-1.00/scripts/config/symbol.c       2004-07-15 08:01:05.000000000 +0200
++++ busybox/scripts/config/symbol.c    2005-06-04 08:20:03.000000000 +0200
+@@ -6,6 +6,7 @@
+ #include <ctype.h>
+ #include <stdlib.h>
+ #include <string.h>
++#include <regex.h>
+ #include <sys/utsname.h>
+ #define LKC_DIRECT_LINK
+@@ -414,7 +415,7 @@
+ bool sym_string_valid(struct symbol *sym, const char *str)
+ {
+-      char ch;
++      signed char ch;
+       switch (sym->type) {
+       case S_STRING:
+@@ -649,6 +650,43 @@
+       return symbol;
+ }
++struct symbol **sym_re_search(const char *pattern)
++{
++      struct symbol *sym, **sym_arr = NULL;
++      int i, cnt, size;
++      regex_t re;
++
++      cnt = size = 0;
++      /* Skip if empty */
++      if (strlen(pattern) == 0)
++              return NULL;
++      if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB|REG_ICASE))
++              return NULL;
++
++      for_all_symbols(i, sym) {
++              if (sym->flags & SYMBOL_CONST || !sym->name)
++                      continue;
++              if (regexec(&re, sym->name, 0, NULL, 0))
++                      continue;
++              if (cnt + 1 >= size) {
++                      void *tmp = sym_arr;
++                      size += 16;
++                      sym_arr = realloc(sym_arr, size * sizeof(struct symbol *));
++                      if (!sym_arr) {
++                              free(tmp);
++                              return NULL;
++                      }
++              }
++              sym_arr[cnt++] = sym;
++      }
++      if (sym_arr)
++              sym_arr[cnt] = NULL;
++      regfree(&re);
++
++      return sym_arr;
++}
++
++
+ struct symbol *sym_check_deps(struct symbol *sym);
+ static struct symbol *sym_check_expr_deps(struct expr *e)
+diff -Nur busybox-1.00/scripts/config/textbox.c busybox/scripts/config/textbox.c
+--- busybox-1.00/scripts/config/textbox.c      2004-07-15 08:01:05.000000000 +0200
++++ busybox/scripts/config/textbox.c   1970-01-01 01:00:00.000000000 +0100
+@@ -1,556 +0,0 @@
+-/*
+- *  textbox.c -- implements the text box
+- *
+- *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+- *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+- *
+- *  This program is free software; you can redistribute it and/or
+- *  modify it under the terms of the GNU General Public License
+- *  as published by the Free Software Foundation; either version 2
+- *  of the License, or (at your option) any later version.
+- *
+- *  This program is distributed in the hope that it will be useful,
+- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- *  GNU General Public License for more details.
+- *
+- *  You should have received a copy of the GNU General Public License
+- *  along with this program; if not, write to the Free Software
+- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+- */
+-
+-#include "dialog.h"
+-
+-static void back_lines (int n);
+-static void print_page (WINDOW * win, int height, int width);
+-static void print_line (WINDOW * win, int row, int width);
+-static char *get_line (void);
+-static void print_position (WINDOW * win, int height, int width);
+-
+-static int hscroll, fd, file_size, bytes_read;
+-static int begin_reached = 1, end_reached, page_length;
+-static char *buf, *page;
+-
+-/*
+- * Display text from a file in a dialog box.
+- */
+-int
+-dialog_textbox (const char *title, const char *file, int height, int width)
+-{
+-    int i, x, y, cur_x, cur_y, fpos, key = 0;
+-    int passed_end;
+-    char search_term[MAX_LEN + 1];
+-    WINDOW *dialog, *text;
+-
+-    search_term[0] = '\0';    /* no search term entered yet */
+-
+-    /* Open input file for reading */
+-    if ((fd = open (file, O_RDONLY)) == -1) {
+-      endwin ();
+-      fprintf (stderr,
+-               "\nCan't open input file in dialog_textbox().\n");
+-      exit (-1);
+-    }
+-    /* Get file size. Actually, 'file_size' is the real file size - 1,
+-       since it's only the last byte offset from the beginning */
+-    if ((file_size = lseek (fd, 0, SEEK_END)) == -1) {
+-      endwin ();
+-      fprintf (stderr, "\nError getting file size in dialog_textbox().\n");
+-      exit (-1);
+-    }
+-    /* Restore file pointer to beginning of file after getting file size */
+-    if (lseek (fd, 0, SEEK_SET) == -1) {
+-      endwin ();
+-      fprintf (stderr, "\nError moving file pointer in dialog_textbox().\n");
+-      exit (-1);
+-    }
+-    /* Allocate space for read buffer */
+-    if ((buf = malloc (BUF_SIZE + 1)) == NULL) {
+-      endwin ();
+-      fprintf (stderr, "\nCan't allocate memory in dialog_textbox().\n");
+-      exit (-1);
+-    }
+-    if ((bytes_read = read (fd, buf, BUF_SIZE)) == -1) {
+-      endwin ();
+-      fprintf (stderr, "\nError reading file in dialog_textbox().\n");
+-      exit (-1);
+-    }
+-    buf[bytes_read] = '\0';   /* mark end of valid data */
+-    page = buf;                       /* page is pointer to start of page to be displayed */
+-
+-    /* center dialog box on screen */
+-    x = (COLS - width) / 2;
+-    y = (LINES - height) / 2;
+-
+-
+-    draw_shadow (stdscr, y, x, height, width);
+-
+-    dialog = newwin (height, width, y, x);
+-    keypad (dialog, TRUE);
+-
+-    /* Create window for text region, used for scrolling text */
+-    text = subwin (dialog, height - 4, width - 2, y + 1, x + 1);
+-    wattrset (text, dialog_attr);
+-    wbkgdset (text, dialog_attr & A_COLOR);
+-
+-    keypad (text, TRUE);
+-
+-    /* register the new window, along with its borders */
+-    draw_box (dialog, 0, 0, height, width, dialog_attr, border_attr);
+-
+-    wattrset (dialog, border_attr);
+-    mvwaddch (dialog, height-3, 0, ACS_LTEE);
+-    for (i = 0; i < width - 2; i++)
+-      waddch (dialog, ACS_HLINE);
+-    wattrset (dialog, dialog_attr);
+-    wbkgdset (dialog, dialog_attr & A_COLOR);
+-    waddch (dialog, ACS_RTEE);
+-
+-    if (title != NULL && strlen(title) >= width-2 ) {
+-      /* truncate long title -- mec */
+-      char * title2 = malloc(width-2+1);
+-      memcpy( title2, title, width-2 );
+-      title2[width-2] = '\0';
+-      title = title2;
+-    }
+-
+-    if (title != NULL) {
+-      wattrset (dialog, title_attr);
+-      mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' ');
+-      waddstr (dialog, (char *)title);
+-      waddch (dialog, ' ');
+-    }
+-    print_button (dialog, " Exit ", height - 2, width / 2 - 4, TRUE);
+-    wnoutrefresh (dialog);
+-    getyx (dialog, cur_y, cur_x);     /* Save cursor position */
+-
+-    /* Print first page of text */
+-    attr_clear (text, height - 4, width - 2, dialog_attr);
+-    print_page (text, height - 4, width - 2);
+-    print_position (dialog, height, width);
+-    wmove (dialog, cur_y, cur_x);     /* Restore cursor position */
+-    wrefresh (dialog);
+-
+-    while ((key != ESC) && (key != '\n')) {
+-      key = wgetch (dialog);
+-      switch (key) {
+-      case 'E':               /* Exit */
+-      case 'e':
+-      case 'X':
+-      case 'x':
+-          delwin (dialog);
+-          free (buf);
+-          close (fd);
+-          return 0;
+-      case 'g':               /* First page */
+-      case KEY_HOME:
+-          if (!begin_reached) {
+-              begin_reached = 1;
+-              /* First page not in buffer? */
+-              if ((fpos = lseek (fd, 0, SEEK_CUR)) == -1) {
+-                  endwin ();
+-                  fprintf (stderr,
+-                    "\nError moving file pointer in dialog_textbox().\n");
+-                  exit (-1);
+-              }
+-              if (fpos > bytes_read) {        /* Yes, we have to read it in */
+-                  if (lseek (fd, 0, SEEK_SET) == -1) {
+-                      endwin ();
+-                      fprintf (stderr, "\nError moving file pointer in "
+-                               "dialog_textbox().\n");
+-                      exit (-1);
+-                  }
+-                  if ((bytes_read = read (fd, buf, BUF_SIZE)) == -1) {
+-                      endwin ();
+-                      fprintf (stderr,
+-                           "\nError reading file in dialog_textbox().\n");
+-                      exit (-1);
+-                  }
+-                  buf[bytes_read] = '\0';
+-              }
+-              page = buf;
+-              print_page (text, height - 4, width - 2);
+-              print_position (dialog, height, width);
+-              wmove (dialog, cur_y, cur_x);   /* Restore cursor position */
+-              wrefresh (dialog);
+-          }
+-          break;
+-      case 'G':               /* Last page */
+-      case KEY_END:
+-
+-          end_reached = 1;
+-          /* Last page not in buffer? */
+-          if ((fpos = lseek (fd, 0, SEEK_CUR)) == -1) {
+-              endwin ();
+-              fprintf (stderr,
+-                    "\nError moving file pointer in dialog_textbox().\n");
+-              exit (-1);
+-          }
+-          if (fpos < file_size) {     /* Yes, we have to read it in */
+-              if (lseek (fd, -BUF_SIZE, SEEK_END) == -1) {
+-                  endwin ();
+-                  fprintf (stderr,
+-                    "\nError moving file pointer in dialog_textbox().\n");
+-                  exit (-1);
+-              }
+-              if ((bytes_read = read (fd, buf, BUF_SIZE)) == -1) {
+-                  endwin ();
+-                  fprintf (stderr,
+-                           "\nError reading file in dialog_textbox().\n");
+-                  exit (-1);
+-              }
+-              buf[bytes_read] = '\0';
+-          }
+-          page = buf + bytes_read;
+-          back_lines (height - 4);
+-          print_page (text, height - 4, width - 2);
+-          print_position (dialog, height, width);
+-          wmove (dialog, cur_y, cur_x);       /* Restore cursor position */
+-          wrefresh (dialog);
+-          break;
+-      case 'K':               /* Previous line */
+-      case 'k':
+-      case KEY_UP:
+-          if (!begin_reached) {
+-              back_lines (page_length + 1);
+-
+-              /* We don't call print_page() here but use scrolling to ensure
+-                 faster screen update. However, 'end_reached' and
+-                 'page_length' should still be updated, and 'page' should
+-                 point to start of next page. This is done by calling
+-                 get_line() in the following 'for' loop. */
+-              scrollok (text, TRUE);
+-              wscrl (text, -1);       /* Scroll text region down one line */
+-              scrollok (text, FALSE);
+-              page_length = 0;
+-              passed_end = 0;
+-              for (i = 0; i < height - 4; i++) {
+-                  if (!i) {
+-                      /* print first line of page */
+-                      print_line (text, 0, width - 2);
+-                      wnoutrefresh (text);
+-                  } else
+-                      /* Called to update 'end_reached' and 'page' */
+-                      get_line ();
+-                  if (!passed_end)
+-                      page_length++;
+-                  if (end_reached && !passed_end)
+-                      passed_end = 1;
+-              }
+-
+-              print_position (dialog, height, width);
+-              wmove (dialog, cur_y, cur_x);   /* Restore cursor position */
+-              wrefresh (dialog);
+-          }
+-          break;
+-      case 'B':               /* Previous page */
+-      case 'b':
+-      case KEY_PPAGE:
+-          if (begin_reached)
+-              break;
+-          back_lines (page_length + height - 4);
+-          print_page (text, height - 4, width - 2);
+-          print_position (dialog, height, width);
+-          wmove (dialog, cur_y, cur_x);
+-          wrefresh (dialog);
+-          break;
+-      case 'J':               /* Next line */
+-      case 'j':
+-      case KEY_DOWN:
+-          if (!end_reached) {
+-              begin_reached = 0;
+-              scrollok (text, TRUE);
+-              scroll (text);  /* Scroll text region up one line */
+-              scrollok (text, FALSE);
+-              print_line (text, height - 5, width - 2);
+-              wnoutrefresh (text);
+-              print_position (dialog, height, width);
+-              wmove (dialog, cur_y, cur_x);   /* Restore cursor position */
+-              wrefresh (dialog);
+-          }
+-          break;
+-      case KEY_NPAGE:         /* Next page */
+-      case ' ':
+-          if (end_reached)
+-              break;
+-
+-          begin_reached = 0;
+-          print_page (text, height - 4, width - 2);
+-          print_position (dialog, height, width);
+-          wmove (dialog, cur_y, cur_x);
+-          wrefresh (dialog);
+-          break;
+-      case '0':               /* Beginning of line */
+-      case 'H':               /* Scroll left */
+-      case 'h':
+-      case KEY_LEFT:
+-          if (hscroll <= 0)
+-              break;
+-
+-          if (key == '0')
+-              hscroll = 0;
+-          else
+-              hscroll--;
+-          /* Reprint current page to scroll horizontally */
+-          back_lines (page_length);
+-          print_page (text, height - 4, width - 2);
+-          wmove (dialog, cur_y, cur_x);
+-          wrefresh (dialog);
+-          break;
+-      case 'L':               /* Scroll right */
+-      case 'l':
+-      case KEY_RIGHT:
+-          if (hscroll >= MAX_LEN)
+-              break;
+-          hscroll++;
+-          /* Reprint current page to scroll horizontally */
+-          back_lines (page_length);
+-          print_page (text, height - 4, width - 2);
+-          wmove (dialog, cur_y, cur_x);
+-          wrefresh (dialog);
+-          break;
+-      case ESC:
+-          break;
+-      }
+-    }
+-
+-    delwin (dialog);
+-    free (buf);
+-    close (fd);
+-    return 1;                 /* ESC pressed */
+-}
+-
+-/*
+- * Go back 'n' lines in text file. Called by dialog_textbox().
+- * 'page' will be updated to point to the desired line in 'buf'.
+- */
+-static void
+-back_lines (int n)
+-{
+-    int i, fpos;
+-
+-    begin_reached = 0;
+-    /* We have to distinguish between end_reached and !end_reached
+-       since at end of file, the line is not ended by a '\n'.
+-       The code inside 'if' basically does a '--page' to move one
+-       character backward so as to skip '\n' of the previous line */
+-    if (!end_reached) {
+-      /* Either beginning of buffer or beginning of file reached? */
+-      if (page == buf) {
+-          if ((fpos = lseek (fd, 0, SEEK_CUR)) == -1) {
+-              endwin ();
+-              fprintf (stderr, "\nError moving file pointer in "
+-                       "back_lines().\n");
+-              exit (-1);
+-          }
+-          if (fpos > bytes_read) {    /* Not beginning of file yet */
+-              /* We've reached beginning of buffer, but not beginning of
+-                 file yet, so read previous part of file into buffer.
+-                 Note that we only move backward for BUF_SIZE/2 bytes,
+-                 but not BUF_SIZE bytes to avoid re-reading again in
+-                 print_page() later */
+-              /* Really possible to move backward BUF_SIZE/2 bytes? */
+-              if (fpos < BUF_SIZE / 2 + bytes_read) {
+-                  /* No, move less then */
+-                  if (lseek (fd, 0, SEEK_SET) == -1) {
+-                      endwin ();
+-                      fprintf (stderr, "\nError moving file pointer in "
+-                               "back_lines().\n");
+-                      exit (-1);
+-                  }
+-                  page = buf + fpos - bytes_read;
+-              } else {        /* Move backward BUF_SIZE/2 bytes */
+-                  if (lseek (fd, -(BUF_SIZE / 2 + bytes_read), SEEK_CUR)
+-                      == -1) {
+-                      endwin ();
+-                      fprintf (stderr, "\nError moving file pointer "
+-                               "in back_lines().\n");
+-                      exit (-1);
+-                  }
+-                  page = buf + BUF_SIZE / 2;
+-              }
+-              if ((bytes_read = read (fd, buf, BUF_SIZE)) == -1) {
+-                  endwin ();
+-                  fprintf (stderr, "\nError reading file in back_lines().\n");
+-                  exit (-1);
+-              }
+-              buf[bytes_read] = '\0';
+-          } else {            /* Beginning of file reached */
+-              begin_reached = 1;
+-              return;
+-          }
+-      }
+-      if (*(--page) != '\n') {        /* '--page' here */
+-          /* Something's wrong... */
+-          endwin ();
+-          fprintf (stderr, "\nInternal error in back_lines().\n");
+-          exit (-1);
+-      }
+-    }
+-    /* Go back 'n' lines */
+-    for (i = 0; i < n; i++)
+-      do {
+-          if (page == buf) {
+-              if ((fpos = lseek (fd, 0, SEEK_CUR)) == -1) {
+-                  endwin ();
+-                  fprintf (stderr,
+-                        "\nError moving file pointer in back_lines().\n");
+-                  exit (-1);
+-              }
+-              if (fpos > bytes_read) {
+-                  /* Really possible to move backward BUF_SIZE/2 bytes? */
+-                  if (fpos < BUF_SIZE / 2 + bytes_read) {
+-                      /* No, move less then */
+-                      if (lseek (fd, 0, SEEK_SET) == -1) {
+-                          endwin ();
+-                          fprintf (stderr, "\nError moving file pointer "
+-                                   "in back_lines().\n");
+-                          exit (-1);
+-                      }
+-                      page = buf + fpos - bytes_read;
+-                  } else {    /* Move backward BUF_SIZE/2 bytes */
+-                      if (lseek (fd, -(BUF_SIZE / 2 + bytes_read),
+-                                 SEEK_CUR) == -1) {
+-                          endwin ();
+-                          fprintf (stderr, "\nError moving file pointer"
+-                                   " in back_lines().\n");
+-                          exit (-1);
+-                      }
+-                      page = buf + BUF_SIZE / 2;
+-                  }
+-                  if ((bytes_read = read (fd, buf, BUF_SIZE)) == -1) {
+-                      endwin ();
+-                      fprintf (stderr, "\nError reading file in "
+-                               "back_lines().\n");
+-                      exit (-1);
+-                  }
+-                  buf[bytes_read] = '\0';
+-              } else {        /* Beginning of file reached */
+-                  begin_reached = 1;
+-                  return;
+-              }
+-          }
+-      } while (*(--page) != '\n');
+-    page++;
+-}
+-
+-/*
+- * Print a new page of text. Called by dialog_textbox().
+- */
+-static void
+-print_page (WINDOW * win, int height, int width)
+-{
+-    int i, passed_end = 0;
+-
+-    page_length = 0;
+-    for (i = 0; i < height; i++) {
+-      print_line (win, i, width);
+-      if (!passed_end)
+-          page_length++;
+-      if (end_reached && !passed_end)
+-          passed_end = 1;
+-    }
+-    wnoutrefresh (win);
+-}
+-
+-/*
+- * Print a new line of text. Called by dialog_textbox() and print_page().
+- */
+-static void
+-print_line (WINDOW * win, int row, int width)
+-{
+-    int y, x;
+-    char *line;
+-
+-    line = get_line ();
+-    line += MIN (strlen (line), hscroll);     /* Scroll horizontally */
+-    wmove (win, row, 0);      /* move cursor to correct line */
+-    waddch (win, ' ');
+-    waddnstr (win, line, MIN (strlen (line), width - 2));
+-
+-    getyx (win, y, x);
+-    /* Clear 'residue' of previous line */
+-#if OLD_NCURSES
+-    {
+-        int i;
+-        for (i = 0; i < width - x; i++)
+-          waddch (win, ' ');
+-    }
+-#else
+-    wclrtoeol(win);
+-#endif
+-}
+-
+-/*
+- * Return current line of text. Called by dialog_textbox() and print_line().
+- * 'page' should point to start of current line before calling, and will be
+- * updated to point to start of next line.
+- */
+-static char *
+-get_line (void)
+-{
+-    int i = 0, fpos;
+-    static char line[MAX_LEN + 1];
+-
+-    end_reached = 0;
+-    while (*page != '\n') {
+-      if (*page == '\0') {
+-          /* Either end of file or end of buffer reached */
+-          if ((fpos = lseek (fd, 0, SEEK_CUR)) == -1) {
+-              endwin ();
+-              fprintf (stderr, "\nError moving file pointer in "
+-                       "get_line().\n");
+-              exit (-1);
+-          }
+-          if (fpos < file_size) {     /* Not end of file yet */
+-              /* We've reached end of buffer, but not end of file yet,
+-                 so read next part of file into buffer */
+-              if ((bytes_read = read (fd, buf, BUF_SIZE)) == -1) {
+-                  endwin ();
+-                  fprintf (stderr, "\nError reading file in get_line().\n");
+-                  exit (-1);
+-              }
+-              buf[bytes_read] = '\0';
+-              page = buf;
+-          } else {
+-              if (!end_reached)
+-                  end_reached = 1;
+-              break;
+-          }
+-      } else if (i < MAX_LEN)
+-          line[i++] = *(page++);
+-      else {
+-          /* Truncate lines longer than MAX_LEN characters */
+-          if (i == MAX_LEN)
+-              line[i++] = '\0';
+-          page++;
+-      }
+-    }
+-    if (i <= MAX_LEN)
+-      line[i] = '\0';
+-    if (!end_reached)
+-      page++;                 /* move pass '\n' */
+-
+-    return line;
+-}
+-
+-/*
+- * Print current position
+- */
+-static void
+-print_position (WINDOW * win, int height, int width)
+-{
+-    int fpos, percent;
+-
+-    if ((fpos = lseek (fd, 0, SEEK_CUR)) == -1) {
+-      endwin ();
+-      fprintf (stderr, "\nError moving file pointer in print_position().\n");
+-      exit (-1);
+-    }
+-    wattrset (win, position_indicator_attr);
+-    wbkgdset (win, position_indicator_attr & A_COLOR);
+-    percent = !file_size ?
+-      100 : ((fpos - bytes_read + page - buf) * 100) / file_size;
+-    wmove (win, height - 3, width - 9);
+-    wprintw (win, "(%3d%%)", percent);
+-}
+diff -Nur busybox-1.00/scripts/config/util.c busybox/scripts/config/util.c
+--- busybox-1.00/scripts/config/util.c 2004-07-15 08:01:05.000000000 +0200
++++ busybox/scripts/config/util.c      2005-06-04 08:20:03.000000000 +0200
+@@ -1,375 +1,109 @@
+ /*
+- *  util.c
++ * Copyright (C) 2002-2005 Roman Zippel <zippel@linux-m68k.org>
++ * Copyright (C) 2002-2005 Sam Ravnborg <sam@ravnborg.org>
+  *
+- *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+- *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+- *
+- *  This program is free software; you can redistribute it and/or
+- *  modify it under the terms of the GNU General Public License
+- *  as published by the Free Software Foundation; either version 2
+- *  of the License, or (at your option) any later version.
+- *
+- *  This program is distributed in the hope that it will be useful,
+- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- *  GNU General Public License for more details.
+- *
+- *  You should have received a copy of the GNU General Public License
+- *  along with this program; if not, write to the Free Software
+- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+- */
+-
+-#include "dialog.h"
+-
+-
+-/* use colors by default? */
+-bool use_colors = 1;
+-
+-char *backtitle = NULL;
+-
+-const char *dialog_result;
+-
+-/*
+- * Attribute values, default is for mono display
++ * Released under the terms of the GNU GPL v2.0.
+  */
+-chtype attributes[] =
+-{
+-    A_NORMAL,                 /* screen_attr */
+-    A_NORMAL,                 /* shadow_attr */
+-    A_NORMAL,                 /* dialog_attr */
+-    A_BOLD,                   /* title_attr */
+-    A_NORMAL,                 /* border_attr */
+-    A_REVERSE,                        /* button_active_attr */
+-    A_DIM,                    /* button_inactive_attr */
+-    A_REVERSE,                        /* button_key_active_attr */
+-    A_BOLD,                   /* button_key_inactive_attr */
+-    A_REVERSE,                        /* button_label_active_attr */
+-    A_NORMAL,                 /* button_label_inactive_attr */
+-    A_NORMAL,                 /* inputbox_attr */
+-    A_NORMAL,                 /* inputbox_border_attr */
+-    A_NORMAL,                 /* searchbox_attr */
+-    A_BOLD,                   /* searchbox_title_attr */
+-    A_NORMAL,                 /* searchbox_border_attr */
+-    A_BOLD,                   /* position_indicator_attr */
+-    A_NORMAL,                 /* menubox_attr */
+-    A_NORMAL,                 /* menubox_border_attr */
+-    A_NORMAL,                 /* item_attr */
+-    A_REVERSE,                        /* item_selected_attr */
+-    A_BOLD,                   /* tag_attr */
+-    A_REVERSE,                        /* tag_selected_attr */
+-    A_BOLD,                   /* tag_key_attr */
+-    A_REVERSE,                        /* tag_key_selected_attr */
+-    A_BOLD,                   /* check_attr */
+-    A_REVERSE,                        /* check_selected_attr */
+-    A_BOLD,                   /* uarrow_attr */
+-    A_BOLD                    /* darrow_attr */
+-};
++#include <string.h>
++#include "lkc.h"
+-#include "colors.h"
+-
+-/*
+- * Table of color values
+- */
+-int color_table[][3] =
++/* file already present in list? If not add it */
++struct file *file_lookup(const char *name)
+ {
+-    {SCREEN_FG, SCREEN_BG, SCREEN_HL},
+-    {SHADOW_FG, SHADOW_BG, SHADOW_HL},
+-    {DIALOG_FG, DIALOG_BG, DIALOG_HL},
+-    {TITLE_FG, TITLE_BG, TITLE_HL},
+-    {BORDER_FG, BORDER_BG, BORDER_HL},
+-    {BUTTON_ACTIVE_FG, BUTTON_ACTIVE_BG, BUTTON_ACTIVE_HL},
+-    {BUTTON_INACTIVE_FG, BUTTON_INACTIVE_BG, BUTTON_INACTIVE_HL},
+-    {BUTTON_KEY_ACTIVE_FG, BUTTON_KEY_ACTIVE_BG, BUTTON_KEY_ACTIVE_HL},
+-    {BUTTON_KEY_INACTIVE_FG, BUTTON_KEY_INACTIVE_BG, BUTTON_KEY_INACTIVE_HL},
+-    {BUTTON_LABEL_ACTIVE_FG, BUTTON_LABEL_ACTIVE_BG, BUTTON_LABEL_ACTIVE_HL},
+-    {BUTTON_LABEL_INACTIVE_FG, BUTTON_LABEL_INACTIVE_BG,
+-     BUTTON_LABEL_INACTIVE_HL},
+-    {INPUTBOX_FG, INPUTBOX_BG, INPUTBOX_HL},
+-    {INPUTBOX_BORDER_FG, INPUTBOX_BORDER_BG, INPUTBOX_BORDER_HL},
+-    {SEARCHBOX_FG, SEARCHBOX_BG, SEARCHBOX_HL},
+-    {SEARCHBOX_TITLE_FG, SEARCHBOX_TITLE_BG, SEARCHBOX_TITLE_HL},
+-    {SEARCHBOX_BORDER_FG, SEARCHBOX_BORDER_BG, SEARCHBOX_BORDER_HL},
+-    {POSITION_INDICATOR_FG, POSITION_INDICATOR_BG, POSITION_INDICATOR_HL},
+-    {MENUBOX_FG, MENUBOX_BG, MENUBOX_HL},
+-    {MENUBOX_BORDER_FG, MENUBOX_BORDER_BG, MENUBOX_BORDER_HL},
+-    {ITEM_FG, ITEM_BG, ITEM_HL},
+-    {ITEM_SELECTED_FG, ITEM_SELECTED_BG, ITEM_SELECTED_HL},
+-    {TAG_FG, TAG_BG, TAG_HL},
+-    {TAG_SELECTED_FG, TAG_SELECTED_BG, TAG_SELECTED_HL},
+-    {TAG_KEY_FG, TAG_KEY_BG, TAG_KEY_HL},
+-    {TAG_KEY_SELECTED_FG, TAG_KEY_SELECTED_BG, TAG_KEY_SELECTED_HL},
+-    {CHECK_FG, CHECK_BG, CHECK_HL},
+-    {CHECK_SELECTED_FG, CHECK_SELECTED_BG, CHECK_SELECTED_HL},
+-    {UARROW_FG, UARROW_BG, UARROW_HL},
+-    {DARROW_FG, DARROW_BG, DARROW_HL},
+-};                            /* color_table */
++      struct file *file;
+-/*
+- * Set window to attribute 'attr'
+- */
+-void
+-attr_clear (WINDOW * win, int height, int width, chtype attr)
+-{
+-    int i, j;
++      for (file = file_list; file; file = file->next) {
++              if (!strcmp(name, file->name))
++                      return file;
++      }
+-    wattrset (win, attr);
+-    for (i = 0; i < height; i++) {
+-      wmove (win, i, 0);
+-      for (j = 0; j < width; j++)
+-          waddch (win, ' ');
+-    }
+-    touchwin (win);
++      file = malloc(sizeof(*file));
++      memset(file, 0, sizeof(*file));
++      file->name = strdup(name);
++      file->next = file_list;
++      file_list = file;
++      return file;
++}
++
++/* write a dependency file as used by kbuild to track dependencies */
++int file_write_dep(const char *name)
++{
++      struct file *file;
++      FILE *out;
++
++      if (!name)
++              name = ".config.cmd";
++      out = fopen(".config.tmp", "w");
++      if (!out)
++              return 1;
++      fprintf(out, "deps_config := \\\n");
++      for (file = file_list; file; file = file->next) {
++              if (file->next)
++                      fprintf(out, "\t%s \\\n", file->name);
++              else
++                      fprintf(out, "\t%s\n", file->name);
++      }
++      fprintf(out, "\n.config include/config.h: $(deps_config)\n\n$(deps_config):\n");
++      fclose(out);
++      rename(".config.tmp", name);
++      return 0;
+ }
+-void dialog_clear (void)
+-{
+-    attr_clear (stdscr, LINES, COLS, screen_attr);
+-    /* Display background title if it exists ... - SLH */
+-    if (backtitle != NULL) {
+-        int i;
+-
+-        wattrset (stdscr, screen_attr);
+-        mvwaddstr (stdscr, 0, 1, (char *)backtitle);
+-        wmove (stdscr, 1, 1);
+-        for (i = 1; i < COLS - 1; i++)
+-            waddch (stdscr, ACS_HLINE);
+-    }
+-    wnoutrefresh (stdscr);
+-}
+-/*
+- * Do some initialization for dialog
+- */
+-void
+-init_dialog (void)
++/* Allocate initial growable sting */
++struct gstr str_new(void)
+ {
+-    initscr ();                       /* Init curses */
+-    keypad (stdscr, TRUE);
+-    cbreak ();
+-    noecho ();
+-
+-
+-    if (use_colors)   /* Set up colors */
+-      color_setup ();
+-
+-
+-    dialog_clear ();
++      struct gstr gs;
++      gs.s = malloc(sizeof(char) * 64);
++      gs.len = 16;
++      strcpy(gs.s, "\0");
++      return gs;
+ }
+-/*
+- * Setup for color display
+- */
+-void
+-color_setup (void)
++/* Allocate and assign growable string */
++struct gstr str_assign(const char *s)
+ {
+-    int i;
+-
+-    if (has_colors ()) {      /* Terminal supports color? */
+-      start_color ();
+-
+-      /* Initialize color pairs */
+-      for (i = 0; i < ATTRIBUTE_COUNT; i++)
+-          init_pair (i + 1, color_table[i][0], color_table[i][1]);
+-
+-      /* Setup color attributes */
+-      for (i = 0; i < ATTRIBUTE_COUNT; i++)
+-          attributes[i] = C_ATTR (color_table[i][2], i + 1);
+-    }
++      struct gstr gs;
++      gs.s = strdup(s);
++      gs.len = strlen(s) + 1;
++      return gs;
+ }
+-/*
+- * End using dialog functions.
+- */
+-void
+-end_dialog (void)
++/* Free storage for growable string */
++void str_free(struct gstr *gs)
+ {
+-    endwin ();
++      if (gs->s)
++              free(gs->s);
++      gs->s = NULL;
++      gs->len = 0;
+ }
+-
+-/*
+- * Print a string of text in a window, automatically wrap around to the
+- * next line if the string is too long to fit on one line. Newline
+- * characters '\n' are replaced by spaces.  We start on a new line
+- * if there is no room for at least 4 nonblanks following a double-space.
+- */
+-void
+-print_autowrap (WINDOW * win, const char *prompt, int width, int y, int x)
++/* Append to growable string */
++void str_append(struct gstr *gs, const char *s)
+ {
+-    int newl, cur_x, cur_y;
+-    int i, prompt_len, room, wlen;
+-    char tempstr[MAX_LEN + 1], *word, *sp, *sp2;
+-
+-    strcpy (tempstr, prompt);
+-
+-    prompt_len = strlen(tempstr);
+-
+-    /*
+-     * Remove newlines
+-     */
+-    for(i=0; i<prompt_len; i++) {
+-      if(tempstr[i] == '\n') tempstr[i] = ' ';
+-    }
+-
+-    if (prompt_len <= width - x * 2) {        /* If prompt is short */
+-      wmove (win, y, (width - prompt_len) / 2);
+-      waddstr (win, tempstr);
+-    } else {
+-      cur_x = x;
+-      cur_y = y;
+-      newl = 1;
+-      word = tempstr;
+-      while (word && *word) {
+-          sp = index(word, ' ');
+-          if (sp)
+-              *sp++ = 0;
+-
+-          /* Wrap to next line if either the word does not fit,
+-             or it is the first word of a new sentence, and it is
+-             short, and the next word does not fit. */
+-          room = width - cur_x;
+-          wlen = strlen(word);
+-          if (wlen > room ||
+-             (newl && wlen < 4 && sp && wlen+1+strlen(sp) > room
+-                   && (!(sp2 = index(sp, ' ')) || wlen+1+(sp2-sp) > room))) {
+-              cur_y++;
+-              cur_x = x;
+-          }
+-          wmove (win, cur_y, cur_x);
+-          waddstr (win, word);
+-          getyx (win, cur_y, cur_x);
+-          cur_x++;
+-          if (sp && *sp == ' ') {
+-              cur_x++;        /* double space */
+-              while (*++sp == ' ');
+-              newl = 1;
+-          } else
+-              newl = 0;
+-          word = sp;
++      size_t l = strlen(gs->s) + strlen(s) + 1;
++      if (l > gs->len) {
++              gs->s   = realloc(gs->s, l);
++              gs->len = l;
+       }
+-    }
+-}
+-
+-/*
+- * Print a button
+- */
+-void
+-print_button (WINDOW * win, const char *label, int y, int x, int selected)
+-{
+-    int i, temp;
+-
+-    wmove (win, y, x);
+-    wattrset (win, selected ? button_active_attr : button_inactive_attr);
+-    waddstr (win, "<");
+-    temp = strspn (label, " ");
+-    label += temp;
+-    wattrset (win, selected ? button_label_active_attr
+-            : button_label_inactive_attr);
+-    for (i = 0; i < temp; i++)
+-      waddch (win, ' ');
+-    wattrset (win, selected ? button_key_active_attr
+-            : button_key_inactive_attr);
+-    waddch (win, label[0]);
+-    wattrset (win, selected ? button_label_active_attr
+-            : button_label_inactive_attr);
+-    waddstr (win, (char *)label + 1);
+-    wattrset (win, selected ? button_active_attr : button_inactive_attr);
+-    waddstr (win, ">");
+-    wmove (win, y, x + temp + 1);
++      strcat(gs->s, s);
+ }
+-/*
+- * Draw a rectangular box with line drawing characters
+- */
+-void
+-draw_box (WINDOW * win, int y, int x, int height, int width,
+-        chtype box, chtype border)
+-{
+-    int i, j;
+-
+-    wattrset (win, 0);
+-    for (i = 0; i < height; i++) {
+-      wmove (win, y + i, x);
+-      for (j = 0; j < width; j++)
+-          if (!i && !j)
+-              waddch (win, border | ACS_ULCORNER);
+-          else if (i == height - 1 && !j)
+-              waddch (win, border | ACS_LLCORNER);
+-          else if (!i && j == width - 1)
+-              waddch (win, box | ACS_URCORNER);
+-          else if (i == height - 1 && j == width - 1)
+-              waddch (win, box | ACS_LRCORNER);
+-          else if (!i)
+-              waddch (win, border | ACS_HLINE);
+-          else if (i == height - 1)
+-              waddch (win, box | ACS_HLINE);
+-          else if (!j)
+-              waddch (win, border | ACS_VLINE);
+-          else if (j == width - 1)
+-              waddch (win, box | ACS_VLINE);
+-          else
+-              waddch (win, box | ' ');
+-    }
+-}
+-
+-/*
+- * Draw shadows along the right and bottom edge to give a more 3D look
+- * to the boxes
+- */
+-void
+-draw_shadow (WINDOW * win, int y, int x, int height, int width)
++/* Append printf formatted string to growable string */
++void str_printf(struct gstr *gs, const char *fmt, ...)
+ {
+-    int i;
+-
+-    if (has_colors ()) {      /* Whether terminal supports color? */
+-      wattrset (win, shadow_attr);
+-      wmove (win, y + height, x + 2);
+-      for (i = 0; i < width; i++)
+-          waddch (win, winch (win) & A_CHARTEXT);
+-      for (i = y + 1; i < y + height + 1; i++) {
+-          wmove (win, i, x + width);
+-          waddch (win, winch (win) & A_CHARTEXT);
+-          waddch (win, winch (win) & A_CHARTEXT);
+-      }
+-      wnoutrefresh (win);
+-    }
++      va_list ap;
++      char s[10000]; /* big enough... */
++      va_start(ap, fmt);
++      vsnprintf(s, sizeof(s), fmt, ap);
++      str_append(gs, s);
++      va_end(ap);
+ }
+-/*
+- *  Return the position of the first alphabetic character in a string.
+- */
+-int
+-first_alpha(const char *string, const char *exempt)
++/* Retreive value of growable string */
++const char *str_get(struct gstr *gs)
+ {
+-      int i, in_paren=0, c;
+-
+-      for (i = 0; i < strlen(string); i++) {
+-              c = tolower(string[i]);
+-
+-              if (strchr("<[(", c)) ++in_paren;
+-              if (strchr(">])", c) && in_paren > 0) --in_paren;
+-
+-              if ((! in_paren) && isalpha(c) &&
+-                   strchr(exempt, c) == 0)
+-                      return i;
+-      }
+-
+-      return 0;
++      return gs->s;
+ }
+-/*
+- * Get the first selected item in the dialog_list_item list.
+- */
+-struct dialog_list_item *
+-first_sel_item(int item_no, struct dialog_list_item ** items)
+-{
+-      int i;
+-
+-      for (i = 0; i < item_no; i++) {
+-              if (items[i]->selected)
+-                      return items[i];
+-      }
+-
+-      return NULL;
+-}
+diff -Nur busybox-1.00/scripts/config/yesno.c busybox/scripts/config/yesno.c
+--- busybox-1.00/scripts/config/yesno.c        2002-12-05 09:41:08.000000000 +0100
++++ busybox/scripts/config/yesno.c     1970-01-01 01:00:00.000000000 +0100
+@@ -1,118 +0,0 @@
+-/*
+- *  yesno.c -- implements the yes/no box
+- *
+- *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+- *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+- *
+- *  This program is free software; you can redistribute it and/or
+- *  modify it under the terms of the GNU General Public License
+- *  as published by the Free Software Foundation; either version 2
+- *  of the License, or (at your option) any later version.
+- *
+- *  This program is distributed in the hope that it will be useful,
+- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- *  GNU General Public License for more details.
+- *
+- *  You should have received a copy of the GNU General Public License
+- *  along with this program; if not, write to the Free Software
+- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+- */
+-
+-#include "dialog.h"
+-
+-/*
+- * Display termination buttons
+- */
+-static void
+-print_buttons(WINDOW *dialog, int height, int width, int selected)
+-{
+-    int x = width / 2 - 10;
+-    int y = height - 2;
+-
+-    print_button (dialog, " Yes ", y, x, selected == 0);
+-    print_button (dialog, "  No  ", y, x + 13, selected == 1);
+-
+-    wmove(dialog, y, x+1 + 13*selected );
+-    wrefresh (dialog);
+-}
+-
+-/*
+- * Display a dialog box with two buttons - Yes and No
+- */
+-int
+-dialog_yesno (const char *title, const char *prompt, int height, int width)
+-{
+-    int i, x, y, key = 0, button = 0;
+-    WINDOW *dialog;
+-
+-    /* center dialog box on screen */
+-    x = (COLS - width) / 2;
+-    y = (LINES - height) / 2;
+-
+-    draw_shadow (stdscr, y, x, height, width);
+-
+-    dialog = newwin (height, width, y, x);
+-    keypad (dialog, TRUE);
+-
+-    draw_box (dialog, 0, 0, height, width, dialog_attr, border_attr);
+-    wattrset (dialog, border_attr);
+-    mvwaddch (dialog, height-3, 0, ACS_LTEE);
+-    for (i = 0; i < width - 2; i++)
+-      waddch (dialog, ACS_HLINE);
+-    wattrset (dialog, dialog_attr);
+-    waddch (dialog, ACS_RTEE);
+-
+-    if (title != NULL && strlen(title) >= width-2 ) {
+-      /* truncate long title -- mec */
+-      char * title2 = malloc(width-2+1);
+-      memcpy( title2, title, width-2 );
+-      title2[width-2] = '\0';
+-      title = title2;
+-    }
+-
+-    if (title != NULL) {
+-      wattrset (dialog, title_attr);
+-      mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' ');
+-      waddstr (dialog, (char *)title);
+-      waddch (dialog, ' ');
+-    }
+-
+-    wattrset (dialog, dialog_attr);
+-    print_autowrap (dialog, prompt, width - 2, 1, 3);
+-
+-    print_buttons(dialog, height, width, 0);
+-
+-    while (key != ESC) {
+-      key = wgetch (dialog);
+-      switch (key) {
+-      case 'Y':
+-      case 'y':
+-          delwin (dialog);
+-          return 0;
+-      case 'N':
+-      case 'n':
+-          delwin (dialog);
+-          return 1;
+-
+-      case TAB:
+-      case KEY_LEFT:
+-      case KEY_RIGHT:
+-          button = ((key == KEY_LEFT ? --button : ++button) < 0)
+-                      ? 1 : (button > 1 ? 0 : button);
+-
+-          print_buttons(dialog, height, width, button);
+-          wrefresh (dialog);
+-          break;
+-      case ' ':
+-      case '\n':
+-          delwin (dialog);
+-          return button;
+-      case ESC:
+-          break;
+-      }
+-    }
+-
+-    delwin (dialog);
+-    return -1;                        /* ESC pressed */
+-}
+diff -Nur busybox-1.00/scripts/config/zconf.tab.c_shipped busybox/scripts/config/zconf.tab.c_shipped
+--- busybox-1.00/scripts/config/zconf.tab.c_shipped    2004-03-15 09:29:08.000000000 +0100
++++ busybox/scripts/config/zconf.tab.c_shipped 2005-06-04 08:20:03.000000000 +0200
+@@ -175,6 +175,8 @@
+ struct symbol *symbol_hash[257];
++static struct menu *current_menu, *current_entry;
++
+ #define YYERROR_VERBOSE
+@@ -227,7 +229,7 @@
+ #  define YYSTACK_ALLOC alloca
+ # else
+ #  ifndef YYSTACK_USE_ALLOCA
+-#   if defined (alloca) || defined (_ALLOCA_H)
++#   if defined (alloca) || (defined (_ALLOCA_H) && defined (__GNUC__))
+ #    define YYSTACK_ALLOC alloca
+ #   else
+ #    ifdef __GNUC__
+@@ -2119,6 +2121,7 @@
+ }
+ #include "lex.zconf.c"
++#include "util.c"
+ #include "confdata.c"
+ #include "expr.c"
+ #include "symbol.c"
+diff -Nur busybox-1.00/scripts/config/zconf.y busybox/scripts/config/zconf.y
+--- busybox-1.00/scripts/config/zconf.y        2003-08-05 07:59:48.000000000 +0200
++++ busybox/scripts/config/zconf.y     2005-06-04 08:20:03.000000000 +0200
+@@ -25,6 +25,8 @@
+ struct symbol *symbol_hash[257];
++static struct menu *current_menu, *current_entry;
++
+ #define YYERROR_VERBOSE
+ %}
+ %expect 40
+@@ -681,6 +683,7 @@
+ }
+ #include "lex.zconf.c"
++#include "util.c"
+ #include "confdata.c"
+ #include "expr.c"
+ #include "symbol.c"
+diff -Nur busybox-1.00/shell/Config.in busybox/shell/Config.in
+--- busybox-1.00/shell/Config.in       2004-09-24 11:09:44.000000000 +0200
++++ busybox/shell/Config.in    2005-06-04 08:20:11.000000000 +0200
+@@ -53,6 +53,17 @@
+       help
+         Enable job control in the ash shell.
++config CONFIG_ASH_TIMEOUT
++        bool "  Enable read timeout support."
++        default n
++        depends on CONFIG_ASH_JOB_CONTROL
++        help
++          This option provides read -t <seconds> support.
++
++        read builtin which allows the function to pass control back 
++        if no character input is read from the terminal within a set
++        number of seconds.
++
+ config CONFIG_ASH_ALIAS
+       bool "  Enable alias support"
+       default y
+diff -Nur busybox-1.00/shell/ash.c busybox/shell/ash.c
+--- busybox-1.00/shell/ash.c   2004-10-08 11:43:34.000000000 +0200
++++ busybox/shell/ash.c        2005-06-04 08:20:11.000000000 +0200
+@@ -3722,27 +3722,13 @@
+ {
+       int repeated = 0;
+ #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
+-      int flg_bb = 0;
+-      char *name = cmd;
+-
+-      if(strchr(name, '/') == NULL && find_applet_by_name(name) != NULL) {
+-              flg_bb = 1;
+-      }
+-      if(flg_bb) {
+-              char **ap;
+-              char **new;
+-
+-              *argv = name;
+-              if(strcmp(name, "busybox")) {
+-                      for (ap = argv; *ap; ap++);
+-                      ap = new = xmalloc((ap - argv + 2) * sizeof(char *));
+-                      *ap++ = cmd = "/bin/busybox";
+-                      while ((*ap++ = *argv++));
+-                      argv = new;
+-                      repeated++;
+-              } else {
+-                      cmd = "/bin/busybox";
+-              }
++      if(find_applet_by_name(cmd) != NULL) {
++              /* re-exec ourselves with the new arguments */
++              execve("/proc/self/exe",argv,envp);
++              /* If proc isn't mounted, try hardcoded path to busybox binary*/
++              execve("/bin/busybox",argv,envp);
++              /* If they called chroot or otherwise made the binary no longer
++               * executable, fall through */
+       }
+ #endif
+@@ -12583,17 +12569,34 @@
+       char *prompt;
+       const char *ifs;
+       char *p;
++#if defined(CONFIG_ASH_TIMEOUT)
++      fd_set set;
++      int timeout;
++      struct timeval timeout_struct;
++      struct termios tty, old_tty;
++#endif
+       int startword;
+       int status;
+       int i;
+       rflag = 0;
+       prompt = NULL;
+-      while ((i = nextopt("p:r")) != '\0') {
++#if defined(CONFIG_ASH_TIMEOUT)
++      timeout = 0;
++
++      while ((i = nextopt("p:rt:")) != '\0')
++#else
++      while ((i = nextopt("p:r")) != '\0')
++#endif
++      {
+               if (i == 'p')
+                       prompt = optionarg;
+-              else
++              else if (i == 'r')
+                       rflag = 1;
++#if defined(CONFIG_ASH_TIMEOUT)
++              else
++                      timeout = atoi(optionarg);
++#endif
+       }
+       if (prompt && isatty(0)) {
+               out2str(prompt);
+@@ -12602,11 +12605,53 @@
+               error("arg count");
+       if ((ifs = bltinlookup("IFS")) == NULL)
+               ifs = defifs;
++#if defined(CONFIG_ASH_TIMEOUT)
++      c = 0;
++#endif
+       status = 0;
+       startword = 1;
+       backslash = 0;
++
+       STARTSTACKSTR(p);
+-      for (;;) {
++#if defined(CONFIG_ASH_TIMEOUT)
++      if (timeout > 0) {
++              tcgetattr(0, &tty);
++              old_tty = tty;
++
++              /* cfmakeraw(...) disables too much; we just do this instead. */
++              tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
++              tcsetattr(0, TCSANOW, &tty);
++
++              FD_ZERO (&set);
++              FD_SET (0, &set);
++
++              timeout_struct.tv_sec = timeout;
++              timeout_struct.tv_usec = 0;
++
++              if ((i = select (FD_SETSIZE, &set, NULL, NULL, &timeout_struct)) == 1)
++              {
++                      read(0, &c, 1);
++                      if(c == '\n' || c == 4) /* Handle newlines and EOF */
++                              i = 0; /* Don't read further... */
++                      else
++                              STPUTC(c, p); /* Keep reading... */
++              }
++              tcsetattr(0, TCSANOW, &old_tty);
++
++              /* Echo the character so the user knows it was read...
++                 Yes, this can be done by setting the ECHO flag, but that
++                 echoes ^D and other control characters at this state */
++              if(c != 0)
++                      write(1, &c, 1);
++
++      } else
++              i = 1;
++
++      for (;i == 1;)
++#else
++      for (;;)
++#endif
++      {
+               if (read(0, &c, 1) != 1) {
+                       status = 1;
+                       break;
+diff -Nur busybox-1.00/shell/lash.c busybox/shell/lash.c
+--- busybox-1.00/shell/lash.c  2004-08-16 10:38:34.000000000 +0200
++++ busybox/shell/lash.c       2005-06-04 08:20:11.000000000 +0200
+@@ -1277,11 +1277,17 @@
+       name = child->argv[0];
+       {
+-          char** argv_l=child->argv;
+-          int argc_l;
+-          for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++);
+-          optind = 1;
+-          run_applet_by_name(name, argc_l, child->argv);
++              char** argv_l=child->argv;
++              int argc_l;
++#ifdef _NEWLIB_VERSION
++              /* newlib uses __getopt_initialized for getopt() in 
++               * addition to optind, see newlib/libc/sys/linux/getopt.c
++               */
++              extern int __getopt_initialized = 0;
++#endif
++              for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++);
++              optind = 1;
++              run_applet_by_name(name, argc_l, child->argv);
+       }
+ #endif
+diff -Nur busybox-1.00/sysdeps/linux/Config.in busybox/sysdeps/linux/Config.in
+--- busybox-1.00/sysdeps/linux/Config.in       2004-05-25 13:30:22.000000000 +0200
++++ busybox/sysdeps/linux/Config.in    2005-06-04 08:20:20.000000000 +0200
+@@ -113,6 +113,13 @@
+         cp = --- # disable applet cp for everyone
++        The file has to be owned by user root, group root and has to be
++        writeable only by root:
++              (chown 0.0 /etc/busybox.conf; chmod 600 /etc/busybox.conf)
++        The busybox executable has to be owned by user root, group
++        root and has to be setuid root for this to work:
++              (chown 0.0 /bin/busybox; chmod 4755 /bin/busybox)
++
+         Robert 'sandman' Griebl has more information here:
+         <url: http://www.softforge.de/bb/suid.html >.
+@@ -221,6 +228,7 @@
+ source coreutils/Config.in
+ source console-tools/Config.in
+ source debianutils/Config.in
++source e2fsprogs/Config.in
+ source editors/Config.in
+ source findutils/Config.in
+ source init/Config.in
+@@ -291,4 +299,3 @@
+ endmenu
+-
+diff -Nur busybox-1.00/sysklogd/Makefile busybox/sysklogd/Makefile
+--- busybox-1.00/sysklogd/Makefile     2004-10-08 09:45:51.000000000 +0200
++++ busybox/sysklogd/Makefile  2005-06-04 08:20:09.000000000 +0200
+@@ -1,6 +1,6 @@
+ # Makefile for busybox
+ #
+-# Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
++# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
+ #
+ # This program is free software; you can redistribute it and/or modify
+ # it under the terms of the GNU General Public License as published by
+@@ -18,7 +18,7 @@
+ #
+ top_srcdir=..
+-top_buildddir=..
++top_builddir=..
+ srcdir=$(top_srcdir)/sysklogd
+ SYSKLOGD_DIR:=./
+ include $(top_builddir)/Rules.mak
+@@ -29,4 +29,3 @@
+ clean:
+       rm -f *.o *.a $(AR_TARGET)
+-
+diff -Nur busybox-1.00/sysklogd/logger.c busybox/sysklogd/logger.c
+--- busybox-1.00/sysklogd/logger.c     2004-08-27 00:18:59.000000000 +0200
++++ busybox/sysklogd/logger.c  2005-06-04 08:20:09.000000000 +0200
+@@ -127,7 +127,7 @@
+               }
+       }
+-      openlog(name, option, (pri | LOG_FACMASK));
++      openlog(name, option, 0);
+       if (optind == argc) {
+               do {
+                       /* read from stdin */
+@@ -152,8 +152,8 @@
+                       message = xrealloc(message, len);
+                       if(!i)
+                               message[0] = 0;
+-                       else
+-                      strcat(message, " ");
++                      else
++                              strcat(message, " ");
+                       strcat(message, *argv);
+                       argv++;
+               }
+diff -Nur busybox-1.00/testsuite/sed/sed-branch-conditional-inverted busybox/testsuite/sed/sed-branch-conditional-inverted
+--- busybox-1.00/testsuite/sed/sed-branch-conditional-inverted 1970-01-01 01:00:00.000000000 +0100
++++ busybox/testsuite/sed/sed-branch-conditional-inverted      2005-06-04 08:20:19.000000000 +0200
+@@ -0,0 +1,14 @@
++busybox sed 's/a/1/;T notone;p;: notone;p'>output <<EOF
++a
++b
++c
++EOF
++cmp -s output - <<EOF
++1
++1
++1
++b
++b
++c
++c
++EOF
+diff -Nur busybox-1.00/util-linux/Config.in busybox/util-linux/Config.in
+--- busybox-1.00/util-linux/Config.in  2004-05-19 13:06:20.000000000 +0200
++++ busybox/util-linux/Config.in       2005-06-04 08:20:22.000000000 +0200
+@@ -5,7 +5,6 @@
+ menu "Linux System Utilities"
+-
+ config CONFIG_DMESG
+       bool "dmesg"
+       default n
+@@ -27,7 +26,6 @@
+         interface to access a graphics display.  Enable this option
+         if you wish to enable the 'fbset' utility.
+-
+ config CONFIG_FEATURE_FBSET_FANCY
+       bool "  Turn on extra fbset options"
+       default n
+@@ -353,5 +351,11 @@
+         value is /etc/mtab, which is where this file is located on most desktop
+         Linux systems.
++config CONFIG_READPROFILE
++      bool "readprofile"
++      default n
++      help
++        This allows you to parse /proc/profile for basic profiling.
++
+ endmenu
+diff -Nur busybox-1.00/util-linux/Makefile busybox/util-linux/Makefile
+--- busybox-1.00/util-linux/Makefile   2004-10-08 09:46:08.000000000 +0200
++++ busybox/util-linux/Makefile        2005-06-04 08:20:22.000000000 +0200
+@@ -1,6 +1,6 @@
+ # Makefile for busybox
+ #
+-# Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
++# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
+ #
+ # This program is free software; you can redistribute it and/or modify
+ # it under the terms of the GNU General Public License as published by
+@@ -18,7 +18,7 @@
+ #
+ top_srcdir=..
+-top_buildddir=..
++top_builddir=..
+ srcdir=$(top_srcdir)/util-linux
+ UTILLINUX_DIR:=./
+ include $(top_builddir)/Rules.mak
+@@ -29,4 +29,3 @@
+ clean:
+       rm -f *.o *.a $(AR_TARGET)
+-
+diff -Nur busybox-1.00/util-linux/Makefile.in busybox/util-linux/Makefile.in
+--- busybox-1.00/util-linux/Makefile.in        2004-10-08 09:46:08.000000000 +0200
++++ busybox/util-linux/Makefile.in     2005-06-04 08:20:22.000000000 +0200
+@@ -44,6 +44,7 @@
+ UTILLINUX-$(CONFIG_RDATE)             +=rdate.o
+ UTILLINUX-$(CONFIG_SWAPONOFF)         +=swaponoff.o
+ UTILLINUX-$(CONFIG_UMOUNT)            +=umount.o
++UTILLINUX-$(CONFIG_READPROFILE)               +=readprofile.o
+ libraries-y+=$(UTILLINUX_DIR)$(UTILLINUX_AR)
+@@ -63,4 +64,3 @@
+ endif
+ endif
+-
+diff -Nur busybox-1.00/util-linux/hwclock.c busybox/util-linux/hwclock.c
+--- busybox-1.00/util-linux/hwclock.c  2004-04-14 19:51:38.000000000 +0200
++++ busybox/util-linux/hwclock.c       2005-06-04 08:20:22.000000000 +0200
+@@ -46,7 +46,7 @@
+       int tm_yday;
+       int tm_isdst;
+ };
+-                
++
+ #define RTC_SET_TIME   _IOW('p', 0x0a, struct linux_rtc_time) /* Set RTC time    */
+ #define RTC_RD_TIME    _IOR('p', 0x09, struct linux_rtc_time) /* Read RTC time   */
+@@ -182,11 +182,11 @@
+       return utc;
+ }
+-#define HWCLOCK_OPT_LOCALTIME 1
+-#define HWCLOCK_OPT_UTC       2
+-#define HWCLOCK_OPT_SHOW      4
+-#define HWCLOCK_OPT_HCTOSYS   8
+-#define HWCLOCK_OPT_SYSTOHC   16
++#define HWCLOCK_OPT_LOCALTIME 0x01
++#define HWCLOCK_OPT_UTC       0x02
++#define HWCLOCK_OPT_SHOW      0x04
++#define HWCLOCK_OPT_HCTOSYS   0x08
++#define HWCLOCK_OPT_SYSTOHC   0x10
+ extern int hwclock_main ( int argc, char **argv )
+ {
+@@ -208,16 +208,16 @@
+       bb_opt_complementaly = "r~ws:w~rs:s~wr:l~u:u~l";
+       opt = bb_getopt_ulflags(argc, argv, "lursw");
+       /* Check only one mode was given */
+-      if(opt & 0x80000000UL) {
++      if(opt & BB_GETOPT_ERROR) {
+               bb_show_usage();
+       }
+       /* If -u or -l wasn't given check if we are using utc */
+-      if (opt & (HWCLOCK_OPT_UTC | HWCLOCK_OPT_LOCALTIME)) 
++      if (opt & (HWCLOCK_OPT_UTC | HWCLOCK_OPT_LOCALTIME))
+               utc = opt & HWCLOCK_OPT_UTC;
+       else
+               utc = check_utc();
+-      
++
+       if (opt & HWCLOCK_OPT_HCTOSYS) {
+               return to_sys_clock ( utc );
+       }
+diff -Nur busybox-1.00/util-linux/readprofile.c busybox/util-linux/readprofile.c
+--- busybox-1.00/util-linux/readprofile.c      1970-01-01 01:00:00.000000000 +0100
++++ busybox/util-linux/readprofile.c   2005-06-04 08:20:22.000000000 +0200
+@@ -0,0 +1,302 @@
++/*
++ *  readprofile.c - used to read /proc/profile
++ *
++ *  Copyright (C) 1994,1996 Alessandro Rubini (rubini@ipvvis.unipv.it)
++ *
++ *   This program is free software; you can redistribute it and/or modify
++ *   it under the terms of the GNU General Public License as published by
++ *   the Free Software Foundation; either version 2 of the License, or
++ *   (at your option) any later version.
++ *
++ *   This program is distributed in the hope that it will be useful,
++ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *   GNU General Public License for more details.
++ *
++ *   You should have received a copy of the GNU General Public License
++ *   along with this program; if not, write to the Free Software
++ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++/*
++ * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL>
++ * - added Native Language Support
++ * 1999-09-01 Stephane Eranian <eranian@cello.hpl.hp.com>
++ * - 64bit clean patch
++ * 3Feb2001 Andrew Morton <andrewm@uow.edu.au>
++ * - -M option to write profile multiplier.
++ * 2001-11-07 Werner Almesberger <wa@almesberger.net>
++ * - byte order auto-detection and -n option
++ * 2001-11-09 Werner Almesberger <wa@almesberger.net>
++ * - skip step size (index 0)
++ * 2002-03-09 John Levon <moz@compsoc.man.ac.uk>
++ * - make maplineno do something
++ * 2002-11-28 Mads Martin Joergensen +
++ * - also try /boot/System.map-`uname -r`
++ * 2003-04-09 Werner Almesberger <wa@almesberger.net>
++ * - fixed off-by eight error and improved heuristics in byte order detection
++ * 2003-08-12 Nikita Danilov <Nikita@Namesys.COM>
++ * - added -s option; example of use:
++ * "readprofile -s -m /boot/System.map-test | grep __d_lookup | sort -n -k3"
++ *
++ * Taken from util-linux and adapted for busybox by
++ * Paul Mundt <lethal@linux-sh.org>.
++ */
++
++#include <errno.h>
++#include <stdio.h>
++#include <fcntl.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <sys/utsname.h>
++
++#include "busybox.h"
++
++#define S_LEN 128
++
++/* These are the defaults */
++static char defaultmap[]="/boot/System.map";
++static char defaultpro[]="/proc/profile";
++
++int readprofile_main(int argc, char **argv)
++{
++      FILE *map;
++      int proFd;
++      char *mapFile, *proFile, *mult=0;
++      unsigned long len=0, indx=1;
++      unsigned long long add0=0;
++      unsigned int step;
++      unsigned int *buf, total, fn_len;
++      unsigned long long fn_add, next_add;          /* current and next address */
++      char fn_name[S_LEN], next_name[S_LEN];   /* current and next name */
++      char mode[8];
++      int c;
++      int optAll=0, optInfo=0, optReset=0, optVerbose=0, optNative=0;
++      int optBins=0, optSub=0;
++      char mapline[S_LEN];
++      int maplineno=1;
++      int header_printed;
++
++#define next (current^1)
++
++      proFile = defaultpro;
++      mapFile = defaultmap;
++
++      while ((c = getopt(argc, argv, "M:m:np:itvarVbs")) != -1) {
++              switch(c) {
++              case 'm':
++                      mapFile = optarg;
++                      break;
++              case 'n':
++                      optNative++;
++                      break;
++              case 'p':
++                      proFile = optarg;
++                      break;
++              case 'a':
++                      optAll++;
++                      break;
++              case 'b':
++                      optBins++;
++                      break;
++              case 's':
++                      optSub++;
++                      break;
++              case 'i':
++                      optInfo++;
++                      break;
++              case 'M':
++                      mult = optarg;
++                      break;
++              case 'r':
++                      optReset++;
++                      break;
++              case 'v':
++                      optVerbose++;
++                      break;
++              default:
++                      bb_show_usage();
++              }
++      }
++
++      if (optReset || mult) {
++              int multiplier, fd, to_write;
++
++              /*
++               * When writing the multiplier, if the length of the write is
++               * not sizeof(int), the multiplier is not changed
++               */
++              if (mult) {
++                      multiplier = strtoul(mult, 0, 10);
++                      to_write = sizeof(int);
++              } else {
++                      multiplier = 0;
++                      to_write = 1;   /* sth different from sizeof(int) */
++              }
++
++              fd = bb_xopen(defaultpro,O_WRONLY);
++              if (fd < 0)
++                      bb_perror_msg_and_die(defaultpro);
++
++              if (write(fd, &multiplier, to_write) != to_write)
++                      bb_perror_msg_and_die("error writing %s", defaultpro);
++
++              close(fd);
++              return EXIT_SUCCESS;
++      }
++
++      /*
++       * Use an fd for the profiling buffer, to skip stdio overhead
++       */
++      if (((proFd = bb_xopen(proFile,O_RDONLY)) < 0)
++          || ((int)(len=lseek(proFd,0,SEEK_END)) < 0)
++          || (lseek(proFd,0,SEEK_SET) < 0))
++              bb_perror_msg_and_die(proFile);
++
++      if (!(buf = xmalloc(len)))
++              bb_perror_nomsg_and_die();
++
++      if (read(proFd,buf,len) != len)
++              bb_perror_msg_and_die(proFile);
++
++      close(proFd);
++
++      if (!optNative) {
++              int entries = len/sizeof(*buf);
++              int big = 0,small = 0,i;
++              unsigned *p;
++
++              for (p = buf+1; p < buf+entries; p++) {
++                      if (*p & ~0U << (sizeof(*buf)*4))
++                              big++;
++                      if (*p & ((1 << (sizeof(*buf)*4))-1))
++                              small++;
++              }
++              if (big > small) {
++                      fprintf(stderr,"Assuming reversed byte order. "
++                              "Use -n to force native byte order.\n");
++                      for (p = buf; p < buf+entries; p++)
++                              for (i = 0; i < sizeof(*buf)/2; i++) {
++                                      unsigned char *b = (unsigned char *) p;
++                                      unsigned char tmp;
++
++                                      tmp = b[i];
++                                      b[i] = b[sizeof(*buf)-i-1];
++                                      b[sizeof(*buf)-i-1] = tmp;
++                              }
++              }
++      }
++
++      step = buf[0];
++      if (optInfo) {
++              printf("Sampling_step: %i\n", step);
++              return EXIT_SUCCESS;
++      }
++
++      total = 0;
++
++      map = bb_xfopen(mapFile, "r");
++      if (map == NULL)
++              bb_perror_msg_and_die(mapFile);
++
++      while (fgets(mapline,S_LEN,map)) {
++              if (sscanf(mapline,"%llx %s %s",&fn_add,mode,fn_name) != 3)
++                      bb_error_msg_and_die("%s(%i): wrong map line",
++                                           mapFile, maplineno);
++
++              if (!strcmp(fn_name,"_stext")) /* only elf works like this */ {
++                      add0 = fn_add;
++                      break;
++              }
++              maplineno++;
++      }
++
++      if (!add0)
++              bb_error_msg_and_die("can't find \"_stext\" in %s\n", mapFile);
++
++      /*
++       * Main loop.
++       */
++      while (fgets(mapline,S_LEN,map)) {
++              unsigned int this = 0;
++
++              if (sscanf(mapline,"%llx %s %s",&next_add,mode,next_name) != 3)
++                      bb_error_msg_and_die("%s(%i): wrong map line\n",
++                                           mapFile, maplineno);
++
++              header_printed = 0;
++
++              /* ignore any LEADING (before a '[tT]' symbol is found)
++                 Absolute symbols */
++              if ((*mode == 'A' || *mode == '?') && total == 0) continue;
++              if (*mode != 'T' && *mode != 't' &&
++                  *mode != 'W' && *mode != 'w')
++                      break;  /* only text is profiled */
++
++              if (indx >= len / sizeof(*buf))
++                      bb_error_msg_and_die("profile address out of range. "
++                                           "Wrong map file?");
++
++              while (indx < (next_add-add0)/step) {
++                      if (optBins && (buf[indx] || optAll)) {
++                              if (!header_printed) {
++                                      printf ("%s:\n", fn_name);
++                                      header_printed = 1;
++                              }
++                              printf ("\t%llx\t%u\n", (indx - 1)*step + add0, buf[indx]);
++                      }
++                      this += buf[indx++];
++              }
++              total += this;
++
++              if (optBins) {
++                      if (optVerbose || this > 0)
++                              printf ("  total\t\t\t\t%u\n", this);
++              } else if ((this || optAll) &&
++                         (fn_len = next_add-fn_add) != 0) {
++                      if (optVerbose)
++                              printf("%016llx %-40s %6i %8.4f\n", fn_add,
++                                     fn_name,this,this/(double)fn_len);
++                      else
++                              printf("%6i %-40s %8.4f\n",
++                                     this,fn_name,this/(double)fn_len);
++                      if (optSub) {
++                              unsigned long long scan;
++
++                              for (scan = (fn_add-add0)/step + 1;
++                                   scan < (next_add-add0)/step; scan++) {
++                                      unsigned long long addr;
++
++                                      addr = (scan - 1)*step + add0;
++                                      printf("\t%#llx\t%s+%#llx\t%u\n",
++                                             addr, fn_name, addr - fn_add,
++                                             buf[scan]);
++                              }
++                      }
++              }
++
++              fn_add = next_add;
++              strcpy(fn_name,next_name);
++
++              maplineno++;
++      }
++
++      /* clock ticks, out of kernel text - probably modules */
++      printf("%6i %s\n", buf[len/sizeof(*buf)-1], "*unknown*");
++
++      /* trailer */
++      if (optVerbose)
++              printf("%016x %-40s %6i %8.4f\n",
++                     0,"total",total,total/(double)(fn_add-add0));
++      else
++              printf("%6i %-40s %8.4f\n",
++                     total,"total",total/(double)(fn_add-add0));
++
++      fclose(map);
++      free(buf);
++
++      return EXIT_SUCCESS;
++}
diff --git a/busybox-lzmacat.diff b/busybox-lzmacat.diff
new file mode 100644 (file)
index 0000000..bc7c687
--- /dev/null
@@ -0,0 +1,971 @@
+diff -urN busybox.snapshot/archival/Config.in busybox-lzmacat/archival/Config.in
+--- busybox.snapshot/archival/Config.in        2005-05-03 21:43:40.000000000 +0200
++++ busybox-lzmacat/archival/Config.in 2005-05-03 21:46:02.000000000 +0200
+@@ -121,6 +121,12 @@
+         gzip is used to compress files.
+         It's probably the most widely used UNIX compression program.
++config CONFIG_LZMACAT
++      bool "lzmacat"
++      default n
++      help
++        lzmacat decompresses a given file to STUOUT
++
+ config CONFIG_RPM2CPIO
+       bool "rpm2cpio"
+       default n
+diff -urN busybox.snapshot/archival/Makefile.in busybox-lzmacat/archival/Makefile.in
+--- busybox.snapshot/archival/Makefile.in      2005-05-03 21:43:40.000000000 +0200
++++ busybox-lzmacat/archival/Makefile.in       2005-05-03 21:46:02.000000000 +0200
+@@ -32,6 +32,7 @@
+ ARCHIVAL-$(CONFIG_DPKG_DEB)   += dpkg_deb.o
+ ARCHIVAL-$(CONFIG_GUNZIP)     += gunzip.o
+ ARCHIVAL-$(CONFIG_GZIP)               += gzip.o
++ARCHIVAL-$(CONFIG_LZMACAT)    += lzmacat.o
+ ARCHIVAL-$(CONFIG_RPM2CPIO)   += rpm2cpio.o
+ ARCHIVAL-$(CONFIG_RPM)                += rpm.o
+ ARCHIVAL-$(CONFIG_TAR)                += tar.o
+diff -urN busybox.snapshot/archival/libunarchive/LzmaDecode.c busybox-lzmacat/archival/libunarchive/LzmaDecode.c
+--- busybox.snapshot/archival/libunarchive/LzmaDecode.c        1970-01-01 01:00:00.000000000 +0100
++++ busybox-lzmacat/archival/libunarchive/LzmaDecode.c 2005-05-03 21:46:02.000000000 +0200
+@@ -0,0 +1,663 @@
++/*
++  LzmaDecode.c
++  LZMA Decoder
++  
++  LZMA SDK 4.05 Copyright (c) 1999-2004 Igor Pavlov (2004-08-25)
++  http://www.7-zip.org/
++
++  LZMA SDK is licensed under two licenses:
++  1) GNU Lesser General Public License (GNU LGPL)
++  2) Common Public License (CPL)
++  It means that you can select one of these two licenses and 
++  follow rules of that license.
++
++  SPECIAL EXCEPTION:
++  Igor Pavlov, as the author of this code, expressly permits you to 
++  statically or dynamically link your code (or bind by name) to the 
++  interfaces of this file without subjecting your linked code to the 
++  terms of the CPL or GNU LGPL. Any modifications or additions 
++  to this file, however, are subject to the LGPL or CPL terms.
++*/
++
++#include "LzmaDecode.h"
++
++#ifndef Byte
++#define Byte unsigned char
++#endif
++
++#define kNumTopBits 24
++#define kTopValue ((UInt32)1 << kNumTopBits)
++
++#define kNumBitModelTotalBits 11
++#define kBitModelTotal (1 << kNumBitModelTotalBits)
++#define kNumMoveBits 5
++
++typedef struct _CRangeDecoder
++{
++  Byte *Buffer;
++  Byte *BufferLim;
++  UInt32 Range;
++  UInt32 Code;
++  #ifdef _LZMA_IN_CB
++  ILzmaInCallback *InCallback;
++  int Result;
++  #endif
++  int ExtraBytes;
++} CRangeDecoder;
++
++Byte RangeDecoderReadByte(CRangeDecoder *rd)
++{
++  if (rd->Buffer == rd->BufferLim)
++  {
++    #ifdef _LZMA_IN_CB
++    UInt32 size;
++    rd->Result = rd->InCallback->Read(rd->InCallback, &rd->Buffer, &size);
++    rd->BufferLim = rd->Buffer + size;
++    if (size == 0)
++    #endif
++    {
++      rd->ExtraBytes = 1;
++      return 0xFF;
++    }
++  }
++  return (*rd->Buffer++);
++}
++
++/* #define ReadByte (*rd->Buffer++) */
++#define ReadByte (RangeDecoderReadByte(rd))
++
++void RangeDecoderInit(CRangeDecoder *rd,
++  #ifdef _LZMA_IN_CB
++    ILzmaInCallback *inCallback
++  #else
++    Byte *stream, UInt32 bufferSize
++  #endif
++    )
++{
++  int i;
++  #ifdef _LZMA_IN_CB
++  rd->InCallback = inCallback;
++  rd->Buffer = rd->BufferLim = 0;
++  #else
++  rd->Buffer = stream;
++  rd->BufferLim = stream + bufferSize;
++  #endif
++  rd->ExtraBytes = 0;
++  rd->Code = 0;
++  rd->Range = (0xFFFFFFFF);
++  for(i = 0; i < 5; i++)
++    rd->Code = (rd->Code << 8) | ReadByte;
++}
++
++#define RC_INIT_VAR UInt32 range = rd->Range; UInt32 code = rd->Code;        
++#define RC_FLUSH_VAR rd->Range = range; rd->Code = code;
++#define RC_NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | ReadByte; }
++
++UInt32 RangeDecoderDecodeDirectBits(CRangeDecoder *rd, int numTotalBits)
++{
++  RC_INIT_VAR
++  UInt32 result = 0;
++  int i;
++  for (i = numTotalBits; i > 0; i--)
++  {
++    /* UInt32 t; */
++    range >>= 1;
++
++    result <<= 1;
++    if (code >= range)
++    {
++      code -= range;
++      result |= 1;
++    }
++    /*
++    t = (code - range) >> 31;
++    t &= 1;
++    code -= range & (t - 1);
++    result = (result + result) | (1 - t);
++    */
++    RC_NORMALIZE
++  }
++  RC_FLUSH_VAR
++  return result;
++}
++
++int RangeDecoderBitDecode(CProb *prob, CRangeDecoder *rd)
++{
++  UInt32 bound = (rd->Range >> kNumBitModelTotalBits) * *prob;
++  if (rd->Code < bound)
++  {
++    rd->Range = bound;
++    *prob += (kBitModelTotal - *prob) >> kNumMoveBits;
++    if (rd->Range < kTopValue)
++    {
++      rd->Code = (rd->Code << 8) | ReadByte;
++      rd->Range <<= 8;
++    }
++    return 0;
++  }
++  else
++  {
++    rd->Range -= bound;
++    rd->Code -= bound;
++    *prob -= (*prob) >> kNumMoveBits;
++    if (rd->Range < kTopValue)
++    {
++      rd->Code = (rd->Code << 8) | ReadByte;
++      rd->Range <<= 8;
++    }
++    return 1;
++  }
++}
++
++#define RC_GET_BIT2(prob, mi, A0, A1) \
++  UInt32 bound = (range >> kNumBitModelTotalBits) * *prob; \
++  if (code < bound) \
++    { A0; range = bound; *prob += (kBitModelTotal - *prob) >> kNumMoveBits; mi <<= 1; } \
++  else \
++    { A1; range -= bound; code -= bound; *prob -= (*prob) >> kNumMoveBits; mi = (mi + mi) + 1; } \
++  RC_NORMALIZE
++
++#define RC_GET_BIT(prob, mi) RC_GET_BIT2(prob, mi, ; , ;)               
++
++int RangeDecoderBitTreeDecode(CProb *probs, int numLevels, CRangeDecoder *rd)
++{
++  int mi = 1;
++  int i;
++  #ifdef _LZMA_LOC_OPT
++  RC_INIT_VAR
++  #endif
++  for(i = numLevels; i > 0; i--)
++  {
++    #ifdef _LZMA_LOC_OPT
++    CProb *prob = probs + mi;
++    RC_GET_BIT(prob, mi)
++    #else
++    mi = (mi + mi) + RangeDecoderBitDecode(probs + mi, rd);
++    #endif
++  }
++  #ifdef _LZMA_LOC_OPT
++  RC_FLUSH_VAR
++  #endif
++  return mi - (1 << numLevels);
++}
++
++int RangeDecoderReverseBitTreeDecode(CProb *probs, int numLevels, CRangeDecoder *rd)
++{
++  int mi = 1;
++  int i;
++  int symbol = 0;
++  #ifdef _LZMA_LOC_OPT
++  RC_INIT_VAR
++  #endif
++  for(i = 0; i < numLevels; i++)
++  {
++    #ifdef _LZMA_LOC_OPT
++    CProb *prob = probs + mi;
++    RC_GET_BIT2(prob, mi, ; , symbol |= (1 << i))
++    #else
++    int bit = RangeDecoderBitDecode(probs + mi, rd);
++    mi = mi + mi + bit;
++    symbol |= (bit << i);
++    #endif
++  }
++  #ifdef _LZMA_LOC_OPT
++  RC_FLUSH_VAR
++  #endif
++  return symbol;
++}
++
++Byte LzmaLiteralDecode(CProb *probs, CRangeDecoder *rd)
++{ 
++  int symbol = 1;
++  #ifdef _LZMA_LOC_OPT
++  RC_INIT_VAR
++  #endif
++  do
++  {
++    #ifdef _LZMA_LOC_OPT
++    CProb *prob = probs + symbol;
++    RC_GET_BIT(prob, symbol)
++    #else
++    symbol = (symbol + symbol) | RangeDecoderBitDecode(probs + symbol, rd);
++    #endif
++  }
++  while (symbol < 0x100);
++  #ifdef _LZMA_LOC_OPT
++  RC_FLUSH_VAR
++  #endif
++  return symbol;
++}
++
++Byte LzmaLiteralDecodeMatch(CProb *probs, CRangeDecoder *rd, Byte matchByte)
++{ 
++  int symbol = 1;
++  #ifdef _LZMA_LOC_OPT
++  RC_INIT_VAR
++  #endif
++  do
++  {
++    int bit;
++    int matchBit = (matchByte >> 7) & 1;
++    matchByte <<= 1;
++    #ifdef _LZMA_LOC_OPT
++    {
++      CProb *prob = probs + ((1 + matchBit) << 8) + symbol;
++      RC_GET_BIT2(prob, symbol, bit = 0, bit = 1)
++    }
++    #else
++    bit = RangeDecoderBitDecode(probs + ((1 + matchBit) << 8) + symbol, rd);
++    symbol = (symbol << 1) | bit;
++    #endif
++    if (matchBit != bit)
++    {
++      while (symbol < 0x100)
++      {
++        #ifdef _LZMA_LOC_OPT
++        CProb *prob = probs + symbol;
++        RC_GET_BIT(prob, symbol)
++        #else
++        symbol = (symbol + symbol) | RangeDecoderBitDecode(probs + symbol, rd);
++        #endif
++      }
++      break;
++    }
++  }
++  while (symbol < 0x100);
++  #ifdef _LZMA_LOC_OPT
++  RC_FLUSH_VAR
++  #endif
++  return symbol;
++}
++
++#define kNumPosBitsMax 4
++#define kNumPosStatesMax (1 << kNumPosBitsMax)
++
++#define kLenNumLowBits 3
++#define kLenNumLowSymbols (1 << kLenNumLowBits)
++#define kLenNumMidBits 3
++#define kLenNumMidSymbols (1 << kLenNumMidBits)
++#define kLenNumHighBits 8
++#define kLenNumHighSymbols (1 << kLenNumHighBits)
++
++#define LenChoice 0
++#define LenChoice2 (LenChoice + 1)
++#define LenLow (LenChoice2 + 1)
++#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
++#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
++#define kNumLenProbs (LenHigh + kLenNumHighSymbols) 
++
++int LzmaLenDecode(CProb *p, CRangeDecoder *rd, int posState)
++{
++  if(RangeDecoderBitDecode(p + LenChoice, rd) == 0)
++    return RangeDecoderBitTreeDecode(p + LenLow +
++        (posState << kLenNumLowBits), kLenNumLowBits, rd);
++  if(RangeDecoderBitDecode(p + LenChoice2, rd) == 0)
++    return kLenNumLowSymbols + RangeDecoderBitTreeDecode(p + LenMid +
++        (posState << kLenNumMidBits), kLenNumMidBits, rd);
++  return kLenNumLowSymbols + kLenNumMidSymbols + 
++      RangeDecoderBitTreeDecode(p + LenHigh, kLenNumHighBits, rd);
++}
++
++#define kNumStates 12
++
++#define kStartPosModelIndex 4
++#define kEndPosModelIndex 14
++#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
++
++#define kNumPosSlotBits 6
++#define kNumLenToPosStates 4
++
++#define kNumAlignBits 4
++#define kAlignTableSize (1 << kNumAlignBits)
++
++#define kMatchMinLen 2
++
++#define IsMatch 0
++#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
++#define IsRepG0 (IsRep + kNumStates)
++#define IsRepG1 (IsRepG0 + kNumStates)
++#define IsRepG2 (IsRepG1 + kNumStates)
++#define IsRep0Long (IsRepG2 + kNumStates)
++#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
++#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
++#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
++#define LenCoder (Align + kAlignTableSize)
++#define RepLenCoder (LenCoder + kNumLenProbs)
++#define Literal (RepLenCoder + kNumLenProbs)
++
++#if Literal != LZMA_BASE_SIZE
++StopCompilingDueBUG
++#endif
++
++#ifdef _LZMA_OUT_READ
++
++typedef struct _LzmaVarState
++{
++  CRangeDecoder RangeDecoder;
++  Byte *Dictionary;
++  UInt32 DictionarySize;
++  UInt32 DictionaryPos;
++  UInt32 GlobalPos;
++  UInt32 Reps[4];
++  int lc;
++  int lp;
++  int pb;
++  int State;
++  int PreviousIsMatch;
++  int RemainLen;
++} LzmaVarState;
++
++int LzmaDecoderInit(
++    unsigned char *buffer, UInt32 bufferSize,
++    int lc, int lp, int pb,
++    unsigned char *dictionary, UInt32 dictionarySize,
++    #ifdef _LZMA_IN_CB
++    ILzmaInCallback *inCallback
++    #else
++    unsigned char *inStream, UInt32 inSize
++    #endif
++    )
++{
++  LzmaVarState *vs = (LzmaVarState *)buffer;
++  CProb *p = (CProb *)(buffer + sizeof(LzmaVarState));
++  UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + lp));
++  UInt32 i;
++  if (bufferSize < numProbs * sizeof(CProb) + sizeof(LzmaVarState))
++    return LZMA_RESULT_NOT_ENOUGH_MEM;
++  vs->Dictionary = dictionary;
++  vs->DictionarySize = dictionarySize;
++  vs->DictionaryPos = 0;
++  vs->GlobalPos = 0;
++  vs->Reps[0] = vs->Reps[1] = vs->Reps[2] = vs->Reps[3] = 1;
++  vs->lc = lc;
++  vs->lp = lp;
++  vs->pb = pb;
++  vs->State = 0;
++  vs->PreviousIsMatch = 0;
++  vs->RemainLen = 0;
++  dictionary[dictionarySize - 1] = 0;
++  for (i = 0; i < numProbs; i++)
++    p[i] = kBitModelTotal >> 1; 
++  RangeDecoderInit(&vs->RangeDecoder, 
++      #ifdef _LZMA_IN_CB
++      inCallback
++      #else
++      inStream, inSize
++      #endif
++  );
++  return LZMA_RESULT_OK;
++}
++
++int LzmaDecode(unsigned char *buffer, 
++    unsigned char *outStream, UInt32 outSize,
++    UInt32 *outSizeProcessed)
++{
++  LzmaVarState *vs = (LzmaVarState *)buffer;
++  CProb *p = (CProb *)(buffer + sizeof(LzmaVarState));
++  CRangeDecoder rd = vs->RangeDecoder;
++  int state = vs->State;
++  int previousIsMatch = vs->PreviousIsMatch;
++  Byte previousByte;
++  UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3];
++  UInt32 nowPos = 0;
++  UInt32 posStateMask = (1 << (vs->pb)) - 1;
++  UInt32 literalPosMask = (1 << (vs->lp)) - 1;
++  int lc = vs->lc;
++  int len = vs->RemainLen;
++  UInt32 globalPos = vs->GlobalPos;
++
++  Byte *dictionary = vs->Dictionary;
++  UInt32 dictionarySize = vs->DictionarySize;
++  UInt32 dictionaryPos = vs->DictionaryPos;
++
++  if (len == -1)
++  {
++    *outSizeProcessed = 0;
++    return LZMA_RESULT_OK;
++  }
++
++  while(len > 0 && nowPos < outSize)
++  {
++    UInt32 pos = dictionaryPos - rep0;
++    if (pos >= dictionarySize)
++      pos += dictionarySize;
++    outStream[nowPos++] = dictionary[dictionaryPos] = dictionary[pos];
++    if (++dictionaryPos == dictionarySize)
++      dictionaryPos = 0;
++    len--;
++  }
++  if (dictionaryPos == 0)
++    previousByte = dictionary[dictionarySize - 1];
++  else
++    previousByte = dictionary[dictionaryPos - 1];
++#else
++
++int LzmaDecode(
++    Byte *buffer, UInt32 bufferSize,
++    int lc, int lp, int pb,
++    #ifdef _LZMA_IN_CB
++    ILzmaInCallback *inCallback,
++    #else
++    unsigned char *inStream, UInt32 inSize,
++    #endif
++    unsigned char *outStream, UInt32 outSize,
++    UInt32 *outSizeProcessed)
++{
++  UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + lp));
++  CProb *p = (CProb *)buffer;
++  CRangeDecoder rd;
++  UInt32 i;
++  int state = 0;
++  int previousIsMatch = 0;
++  Byte previousByte = 0;
++  UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1;
++  UInt32 nowPos = 0;
++  UInt32 posStateMask = (1 << pb) - 1;
++  UInt32 literalPosMask = (1 << lp) - 1;
++  int len = 0;
++  if (bufferSize < numProbs * sizeof(CProb))
++    return LZMA_RESULT_NOT_ENOUGH_MEM;
++  for (i = 0; i < numProbs; i++)
++    p[i] = kBitModelTotal >> 1; 
++  RangeDecoderInit(&rd, 
++      #ifdef _LZMA_IN_CB
++      inCallback
++      #else
++      inStream, inSize
++      #endif
++      );
++#endif
++
++  *outSizeProcessed = 0;
++  while(nowPos < outSize)
++  {
++    int posState = (int)(
++        (nowPos 
++        #ifdef _LZMA_OUT_READ
++        + globalPos
++        #endif
++        )
++        & posStateMask);
++    #ifdef _LZMA_IN_CB
++    if (rd.Result != LZMA_RESULT_OK)
++      return rd.Result;
++    #endif
++    if (rd.ExtraBytes != 0)
++      return LZMA_RESULT_DATA_ERROR;
++    if (RangeDecoderBitDecode(p + IsMatch + (state << kNumPosBitsMax) + posState, &rd) == 0)
++    {
++      CProb *probs = p + Literal + (LZMA_LIT_SIZE * 
++        (((
++        (nowPos 
++        #ifdef _LZMA_OUT_READ
++        + globalPos
++        #endif
++        )
++        & literalPosMask) << lc) + (previousByte >> (8 - lc))));
++
++      if (state < 4) state = 0;
++      else if (state < 10) state -= 3;
++      else state -= 6;
++      if (previousIsMatch)
++      {
++        Byte matchByte;
++        #ifdef _LZMA_OUT_READ
++        UInt32 pos = dictionaryPos - rep0;
++        if (pos >= dictionarySize)
++          pos += dictionarySize;
++        matchByte = dictionary[pos];
++        #else
++        matchByte = outStream[nowPos - rep0];
++        #endif
++        previousByte = LzmaLiteralDecodeMatch(probs, &rd, matchByte);
++        previousIsMatch = 0;
++      }
++      else
++        previousByte = LzmaLiteralDecode(probs, &rd);
++      outStream[nowPos++] = previousByte;
++      #ifdef _LZMA_OUT_READ
++      dictionary[dictionaryPos] = previousByte;
++      if (++dictionaryPos == dictionarySize)
++        dictionaryPos = 0;
++      #endif
++    }
++    else             
++    {
++      previousIsMatch = 1;
++      if (RangeDecoderBitDecode(p + IsRep + state, &rd) == 1)
++      {
++        if (RangeDecoderBitDecode(p + IsRepG0 + state, &rd) == 0)
++        {
++          if (RangeDecoderBitDecode(p + IsRep0Long + (state << kNumPosBitsMax) + posState, &rd) == 0)
++          {
++            #ifdef _LZMA_OUT_READ
++            UInt32 pos;
++            #endif
++            if (
++               (nowPos 
++                #ifdef _LZMA_OUT_READ
++                + globalPos
++                #endif
++               )
++               == 0)
++              return LZMA_RESULT_DATA_ERROR;
++            state = state < 7 ? 9 : 11;
++            #ifdef _LZMA_OUT_READ
++            pos = dictionaryPos - rep0;
++            if (pos >= dictionarySize)
++              pos += dictionarySize;
++            previousByte = dictionary[pos];
++            dictionary[dictionaryPos] = previousByte;
++            if (++dictionaryPos == dictionarySize)
++              dictionaryPos = 0;
++            #else
++            previousByte = outStream[nowPos - rep0];
++            #endif
++            outStream[nowPos++] = previousByte;
++            continue;
++          }
++        }
++        else
++        {
++          UInt32 distance;
++          if(RangeDecoderBitDecode(p + IsRepG1 + state, &rd) == 0)
++            distance = rep1;
++          else 
++          {
++            if(RangeDecoderBitDecode(p + IsRepG2 + state, &rd) == 0)
++              distance = rep2;
++            else
++            {
++              distance = rep3;
++              rep3 = rep2;
++            }
++            rep2 = rep1;
++          }
++          rep1 = rep0;
++          rep0 = distance;
++        }
++        len = LzmaLenDecode(p + RepLenCoder, &rd, posState);
++        state = state < 7 ? 8 : 11;
++      }
++      else
++      {
++        int posSlot;
++        rep3 = rep2;
++        rep2 = rep1;
++        rep1 = rep0;
++        state = state < 7 ? 7 : 10;
++        len = LzmaLenDecode(p + LenCoder, &rd, posState);
++        posSlot = RangeDecoderBitTreeDecode(p + PosSlot +
++            ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << 
++            kNumPosSlotBits), kNumPosSlotBits, &rd);
++        if (posSlot >= kStartPosModelIndex)
++        {
++          int numDirectBits = ((posSlot >> 1) - 1);
++          rep0 = ((2 | ((UInt32)posSlot & 1)) << numDirectBits);
++          if (posSlot < kEndPosModelIndex)
++          {
++            rep0 += RangeDecoderReverseBitTreeDecode(
++                p + SpecPos + rep0 - posSlot - 1, numDirectBits, &rd);
++          }
++          else
++          {
++            rep0 += RangeDecoderDecodeDirectBits(&rd, 
++                numDirectBits - kNumAlignBits) << kNumAlignBits;
++            rep0 += RangeDecoderReverseBitTreeDecode(p + Align, kNumAlignBits, &rd);
++          }
++        }
++        else
++          rep0 = posSlot;
++        rep0++;
++      }
++      if (rep0 == (UInt32)(0))
++      {
++        /* it's for stream version */
++        len = -1;
++        break;
++      }
++      if (rep0 > nowPos 
++        #ifdef _LZMA_OUT_READ
++        + globalPos
++        #endif
++        )
++      {
++        return LZMA_RESULT_DATA_ERROR;
++      }
++      len += kMatchMinLen;
++      do
++      {
++        #ifdef _LZMA_OUT_READ
++        UInt32 pos = dictionaryPos - rep0;
++        if (pos >= dictionarySize)
++          pos += dictionarySize;
++        previousByte = dictionary[pos];
++        dictionary[dictionaryPos] = previousByte;
++        if (++dictionaryPos == dictionarySize)
++          dictionaryPos = 0;
++        #else
++        previousByte = outStream[nowPos - rep0];
++        #endif
++        outStream[nowPos++] = previousByte;
++        len--;
++      }
++      while(len > 0 && nowPos < outSize);
++    }
++  }
++
++  #ifdef _LZMA_OUT_READ
++  vs->RangeDecoder = rd;
++  vs->DictionaryPos = dictionaryPos;
++  vs->GlobalPos = globalPos + nowPos;
++  vs->Reps[0] = rep0;
++  vs->Reps[1] = rep1;
++  vs->Reps[2] = rep2;
++  vs->Reps[3] = rep3;
++  vs->State = state;
++  vs->PreviousIsMatch = previousIsMatch;
++  vs->RemainLen = len;
++  #endif
++
++  *outSizeProcessed = nowPos;
++  return LZMA_RESULT_OK;
++}
+diff -urN busybox.snapshot/archival/libunarchive/LzmaDecode.h busybox-lzmacat/archival/libunarchive/LzmaDecode.h
+--- busybox.snapshot/archival/libunarchive/LzmaDecode.h        1970-01-01 01:00:00.000000000 +0100
++++ busybox-lzmacat/archival/libunarchive/LzmaDecode.h 2005-05-03 21:46:02.000000000 +0200
+@@ -0,0 +1,100 @@
++/* 
++  LzmaDecode.h
++  LZMA Decoder interface
++
++  LZMA SDK 4.05 Copyright (c) 1999-2004 Igor Pavlov (2004-08-25)
++  http://www.7-zip.org/
++
++  LZMA SDK is licensed under two licenses:
++  1) GNU Lesser General Public License (GNU LGPL)
++  2) Common Public License (CPL)
++  It means that you can select one of these two licenses and 
++  follow rules of that license.
++
++  SPECIAL EXCEPTION:
++  Igor Pavlov, as the author of this code, expressly permits you to 
++  statically or dynamically link your code (or bind by name) to the 
++  interfaces of this file without subjecting your linked code to the 
++  terms of the CPL or GNU LGPL. Any modifications or additions 
++  to this file, however, are subject to the LGPL or CPL terms.
++*/
++
++#ifndef __LZMADECODE_H
++#define __LZMADECODE_H
++
++/* #define _LZMA_IN_CB */
++/* Use callback for input data */
++
++/* #define _LZMA_OUT_READ */
++/* Use read function for output data */
++
++/* #define _LZMA_PROB32 */
++/* It can increase speed on some 32-bit CPUs, 
++   but memory usage will be doubled in that case */
++
++/* #define _LZMA_LOC_OPT */
++/* Enable local speed optimizations inside code */
++
++#ifndef UInt32
++#ifdef _LZMA_UINT32_IS_ULONG
++#define UInt32 unsigned long
++#else
++#define UInt32 unsigned int
++#endif
++#endif
++
++#ifdef _LZMA_PROB32
++#define CProb UInt32
++#else
++#define CProb unsigned short
++#endif
++
++#define LZMA_RESULT_OK 0
++#define LZMA_RESULT_DATA_ERROR 1
++#define LZMA_RESULT_NOT_ENOUGH_MEM 2
++
++#ifdef _LZMA_IN_CB
++typedef struct _ILzmaInCallback
++{
++  int (*Read)(void *object, unsigned char **buffer, UInt32 *bufferSize);
++} ILzmaInCallback;
++#endif
++
++#define LZMA_BASE_SIZE 1846
++#define LZMA_LIT_SIZE 768
++
++/* 
++bufferSize = (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp)))* sizeof(CProb)
++bufferSize += 100 in case of _LZMA_OUT_READ
++by default CProb is unsigned short, 
++but if specify _LZMA_PROB_32, CProb will be UInt32(unsigned int)
++*/
++
++#ifdef _LZMA_OUT_READ
++int LzmaDecoderInit(
++    unsigned char *buffer, UInt32 bufferSize,
++    int lc, int lp, int pb,
++    unsigned char *dictionary, UInt32 dictionarySize,
++  #ifdef _LZMA_IN_CB
++    ILzmaInCallback *inCallback
++  #else
++    unsigned char *inStream, UInt32 inSize
++  #endif
++);
++#endif
++
++int LzmaDecode(
++    unsigned char *buffer, 
++  #ifndef _LZMA_OUT_READ
++    UInt32 bufferSize,
++    int lc, int lp, int pb,
++  #ifdef _LZMA_IN_CB
++    ILzmaInCallback *inCallback,
++  #else
++    unsigned char *inStream, UInt32 inSize,
++  #endif
++  #endif
++    unsigned char *outStream, UInt32 outSize,
++    UInt32 *outSizeProcessed);
++
++#endif
+diff -urN busybox.snapshot/archival/libunarchive/Makefile.in busybox-lzmacat/archival/libunarchive/Makefile.in
+--- busybox.snapshot/archival/libunarchive/Makefile.in 2005-05-03 21:43:40.000000000 +0200
++++ busybox-lzmacat/archival/libunarchive/Makefile.in  2005-05-03 21:46:02.000000000 +0200
+@@ -64,6 +64,7 @@
+ LIBUNARCHIVE-$(CONFIG_FEATURE_DEB_TAR_GZ) += $(GUNZIP_FILES) get_header_tar_gz.o
+ LIBUNARCHIVE-$(CONFIG_FEATURE_DEB_TAR_BZ2) += decompress_bunzip2.o get_header_tar_bz2.o
+ LIBUNARCHIVE-$(CONFIG_GUNZIP) += $(GUNZIP_FILES)
++LIBUNARCHIVE-$(CONFIG_LZMACAT) += LzmaDecode.o
+ LIBUNARCHIVE-$(CONFIG_FEATURE_GUNZIP_UNCOMPRESS) += decompress_uncompress.o
+ LIBUNARCHIVE-$(CONFIG_RPM2CPIO) += $(GUNZIP_FILES) get_header_cpio.o
+ LIBUNARCHIVE-$(CONFIG_RPM) += $(GUNZIP_FILES) get_header_cpio.o
+diff -urN busybox.snapshot/archival/lzmacat.c busybox-lzmacat/archival/lzmacat.c
+--- busybox.snapshot/archival/lzmacat.c        1970-01-01 01:00:00.000000000 +0100
++++ busybox-lzmacat/archival/lzmacat.c 2005-05-03 22:45:20.000000000 +0200
+@@ -0,0 +1,130 @@
++/* vi: set sw=4 ts=4: */
++/*
++ *  Modified for busybox by Thomas Lundquist <thomasez@zelow.no>
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or
++ *  (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ */
++/* 
++    Ming-Ching Tiew mctiew@yahoo.com
++    9th March 2005 
++    GPL source
++ */
++#include <stdio.h>
++#include <stdlib.h>
++#include <getopt.h>
++#include "busybox.h"
++#include "libunarchive/LzmaDecode.h"
++
++int lzmacat(char *filename);
++
++int lzmacat_main(int argc, char **argv)
++{
++      char *filename;
++      unsigned long opt;
++
++      opt = bb_getopt_ulflags(argc, argv, "");
++
++      filename = argv[optind];
++
++      if (!filename) {
++              bb_error_msg_and_die("Need a filename, lzmacat -h for help.");
++      }
++
++      lzmacat(filename);
++
++
++      /* The lzmacat function is simple enough to error and die 
++         all by itself, so, if we are here, it all went well */
++      return 0;
++}
++
++int lzmacat(char *filename)
++{
++      FILE *fp;
++      unsigned long size;
++      unsigned int outsize;
++      unsigned char prop0;
++      unsigned int dictsize;
++      unsigned int zero;
++      int result, lzma_workspace_size;
++      char *s, *d, *lzma_workspace;
++      int lp, lc, pb;
++
++      fp = bb_xfopen(filename, "r");
++
++      if (fp == NULL) {
++              bb_error_msg_and_die("No such file\n");
++      }
++      // to get the file size 
++      fseek(fp, 0L, SEEK_END);
++
++      // compressed data is file size - 13
++      size = ftell(fp) - 13;
++
++      // allocate just enough memory
++      s = (char *) malloc(size);
++
++      // move back up   
++      fseek(fp, 0L, SEEK_SET);
++
++      // read the property value
++      fread(&prop0, 1, 1, fp);
++
++      if (prop0 > 5 * 9 * 5) {
++              bb_error_msg_and_die("invalid file format!\n");
++      }
++      // read the dictionary size
++      fread(&dictsize, 4, 1, fp);
++
++      // read the original file size
++      fread(&outsize, 4, 1, fp);
++      if (outsize < size) {
++              bb_error_msg_and_die("invalid file size!\n");
++      }
++      // ignore file size greater than 4 bytes
++      fread(&zero, 4, 1, fp);
++      if (zero != 0) {
++              bb_error_msg_and_die("invalid file or too big!\n");
++      }
++      // read the whole file
++      fread(s, size, 1, fp);
++      fclose(fp);
++
++      d = (char *) malloc(outsize);
++
++      // calculate the properties
++      for (pb = 0; prop0 >= (9 * 5); pb++, prop0 -= (9 * 5));
++      for (lp = 0; prop0 >= 9; lp++, prop0 -= 9);
++      lc = prop0;
++      lzma_workspace_size =
++              (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp))) * sizeof(CProb);
++      lzma_workspace = (char *) malloc(lzma_workspace_size);
++
++      result = LzmaDecode(lzma_workspace, lzma_workspace_size, lc, lp, pb,
++                                              s, size, d, outsize, &outsize);
++
++      if (result != 0) {
++              bb_perror_msg_and_die("decode error=%d\n", result);
++      }
++
++      fwrite(d, outsize, 1, stdout);
++      free(s);
++      free(d);
++      free(lzma_workspace);
++
++      /* All ok */
++      return 0;
++
++}
+diff -urN busybox.snapshot/include/applets.h busybox-lzmacat/include/applets.h
+--- busybox.snapshot/include/applets.h 2005-05-03 21:43:58.000000000 +0200
++++ busybox-lzmacat/include/applets.h  2005-05-03 21:46:02.000000000 +0200
+@@ -368,6 +368,9 @@
+ #ifdef CONFIG_LSMOD
+       APPLET(lsmod, lsmod_main, _BB_DIR_SBIN, _BB_SUID_NEVER)
+ #endif
++#ifdef CONFIG_LZMACAT
++      APPLET(lzmacat, lzmacat_main, _BB_DIR_BIN, _BB_SUID_NEVER)
++#endif
+ #ifdef CONFIG_MAKEDEVS
+       APPLET(makedevs, makedevs_main, _BB_DIR_SBIN, _BB_SUID_NEVER)
+ #endif
+diff -urN busybox.snapshot/include/usage.h busybox-lzmacat/include/usage.h
+--- busybox.snapshot/include/usage.h   2005-05-03 21:43:58.000000000 +0200
++++ busybox-lzmacat/include/usage.h    2005-05-03 21:46:02.000000000 +0200
+@@ -1595,6 +1595,11 @@
+ #define lsmod_full_usage \
+       "List the currently loaded kernel modules."
++#define lzmacat_trivial_usage \
++      "[FILE]"
++#define lzmacat_full_usage \
++      "Decompresses [FILE] to STDOUT."
++
+ #define makedevs_trivial_usage \
+       "NAME TYPE MAJOR MINOR FIRST LAST [s]"
+ #define makedevs_full_usage \
This page took 2.185634 seconds and 4 git commands to generate.