Forward-port the mdadm tool from the Gentoo Busybox-1.1.3.
Should handle all types of metadata 0.90, 1.0, 1.1, 1.2.
If /etc/mdadm.conf does not exist in the initrd, it is created first, by
scanning devices, and then it is used.

Signed-off-by: Robin H. Johnson <robbat2@gentoo.org>

diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/Config.in busybox-1.7.4+gentoo+mdadm/Config.in
--- busybox-1.7.4+gentoo/Config.in	2007-09-03 04:48:58.000000000 -0700
+++ busybox-1.7.4+gentoo+mdadm/Config.in	2008-03-11 10:31:00.000000000 -0700
@@ -499,2 +499,3 @@
 source e2fsprogs/Config.in
+source mdadm/Config.in
 source modutils/Config.in
diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/include/applets.h busybox-1.7.4+gentoo+mdadm/include/applets.h
--- busybox-1.7.4+gentoo/include/applets.h	2008-03-11 10:25:43.000000000 -0700
+++ busybox-1.7.4+gentoo+mdadm/include/applets.h	2008-03-11 10:32:22.000000000 -0700
@@ -223,2 +223,3 @@
 USE_MD5SUM(APPLET_ODDNAME(md5sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_NEVER, md5sum))
+USE_MDADM(APPLET(mdadm, _BB_DIR_SBIN, _BB_SUID_NEVER))
 USE_MDEV(APPLET(mdev, _BB_DIR_SBIN, _BB_SUID_NEVER))
diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/include/usage.h busybox-1.7.4+gentoo+mdadm/include/usage.h
--- busybox-1.7.4+gentoo/include/usage.h	2008-03-11 10:19:04.000000000 -0700
+++ busybox-1.7.4+gentoo+mdadm/include/usage.h	2008-03-11 10:31:00.000000000 -0700
@@ -2048,2 +2048,7 @@
 
+#define mdadm_trivial_usage \
+	""
+#define mdadm_full_usage \
+	"Assemble or Examine the mdadm arrays."
+
 #define mdev_trivial_usage \
diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/Makefile busybox-1.7.4+gentoo+mdadm/Makefile
--- busybox-1.7.4+gentoo/Makefile	2007-11-23 20:34:41.000000000 -0800
+++ busybox-1.7.4+gentoo+mdadm/Makefile	2008-03-11 10:31:49.000000000 -0700
@@ -442,6 +442,7 @@
 		libpwdgrp/ \
 		loginutils/ \
 		miscutils/ \
+		mdadm/ \
 		modutils/ \
 		networking/ \
 		networking/libiproute/ \
diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/mdadm/bitmap.h busybox-1.7.4+gentoo+mdadm/mdadm/bitmap.h
--- busybox-1.7.4+gentoo/mdadm/bitmap.h	1969-12-31 16:00:00.000000000 -0800
+++ busybox-1.7.4+gentoo+mdadm/mdadm/bitmap.h	2008-03-11 10:31:00.000000000 -0700
@@ -0,0 +1,287 @@
+/*
+ * bitmap.h: Copyright (C) Peter T. Breuer (ptb@ot.uc3m.es) 2003
+ *
+ * additions: Copyright (C) 2003-2004, Paul Clements, SteelEye Technology, Inc.
+ */
+#ifndef BITMAP_H
+#define BITMAP_H 1
+
+#define BITMAP_MAJOR_LO 3
+/* version 4 insists the bitmap is in little-endian order
+ * with version 3, it is host-endian which is non-portable
+ */
+#define BITMAP_MAJOR_HI 4
+#define	BITMAP_MAJOR_HOSTENDIAN 3
+
+#define BITMAP_MINOR 39
+
+/*
+ * in-memory bitmap:
+ *
+ * Use 16 bit block counters to track pending writes to each "chunk".
+ * The 2 high order bits are special-purpose, the first is a flag indicating
+ * whether a resync is needed.  The second is a flag indicating whether a
+ * resync is active.
+ * This means that the counter is actually 14 bits:
+ *
+ * +--------+--------+------------------------------------------------+
+ * | resync | resync |               counter                          |
+ * | needed | active |                                                |
+ * |  (0-1) |  (0-1) |              (0-16383)                         |
+ * +--------+--------+------------------------------------------------+
+ *
+ * The "resync needed" bit is set when:
+ *    a '1' bit is read from storage at startup.
+ *    a write request fails on some drives
+ *    a resync is aborted on a chunk with 'resync active' set
+ * It is cleared (and resync-active set) when a resync starts across all drives
+ * of the chunk.
+ *
+ *
+ * The "resync active" bit is set when:
+ *    a resync is started on all drives, and resync_needed is set.
+ *       resync_needed will be cleared (as long as resync_active wasn't already set).
+ * It is cleared when a resync completes.
+ *
+ * The counter counts pending write requests, plus the on-disk bit.
+ * When the counter is '1' and the resync bits are clear, the on-disk
+ * bit can be cleared aswell, thus setting the counter to 0.
+ * When we set a bit, or in the counter (to start a write), if the fields is
+ * 0, we first set the disk bit and set the counter to 1.
+ *
+ * If the counter is 0, the on-disk bit is clear and the stipe is clean
+ * Anything that dirties the stipe pushes the counter to 2 (at least)
+ * and sets the on-disk bit (lazily).
+ * If a periodic sweep find the counter at 2, it is decremented to 1.
+ * If the sweep find the counter at 1, the on-disk bit is cleared and the
+ * counter goes to zero.
+ *
+ * Also, we'll hijack the "map" pointer itself and use it as two 16 bit block
+ * counters as a fallback when "page" memory cannot be allocated:
+ *
+ * Normal case (page memory allocated):
+ *
+ *     page pointer (32-bit)
+ *
+ *     [ ] ------+
+ *               |
+ *               +-------> [   ][   ]..[   ] (4096 byte page == 2048 counters)
+ *                          c1   c2    c2048
+ *
+ * Hijacked case (page memory allocation failed):
+ *
+ *     hijacked page pointer (32-bit)
+ *
+ *     [		  ][		  ] (no page memory allocated)
+ *      counter #1 (16-bit) counter #2 (16-bit)
+ *
+ */
+
+#ifdef __KERNEL__
+
+#define PAGE_BITS (PAGE_SIZE << 3)
+#define PAGE_BIT_SHIFT (PAGE_SHIFT + 3)
+
+typedef __u16 bitmap_counter_t;
+#define COUNTER_BITS 16
+#define COUNTER_BIT_SHIFT 4
+#define COUNTER_BYTE_RATIO (COUNTER_BITS / 8)
+#define COUNTER_BYTE_SHIFT (COUNTER_BIT_SHIFT - 3)
+
+#define NEEDED_MASK ((bitmap_counter_t) (1 << (COUNTER_BITS - 1)))
+#define RESYNC_MASK ((bitmap_counter_t) (1 << (COUNTER_BITS - 2)))
+#define COUNTER_MAX ((bitmap_counter_t) RESYNC_MASK - 1)
+#define NEEDED(x) (((bitmap_counter_t) x) & NEEDED_MASK)
+#define RESYNC(x) (((bitmap_counter_t) x) & RESYNC_MASK)
+#define COUNTER(x) (((bitmap_counter_t) x) & COUNTER_MAX)
+
+/* how many counters per page? */
+#define PAGE_COUNTER_RATIO (PAGE_BITS / COUNTER_BITS)
+/* same, except a shift value for more efficient bitops */
+#define PAGE_COUNTER_SHIFT (PAGE_BIT_SHIFT - COUNTER_BIT_SHIFT)
+/* same, except a mask value for more efficient bitops */
+#define PAGE_COUNTER_MASK  (PAGE_COUNTER_RATIO - 1)
+
+#define BITMAP_BLOCK_SIZE 512
+#define BITMAP_BLOCK_SHIFT 9
+
+/* how many blocks per chunk? (this is variable) */
+#define CHUNK_BLOCK_RATIO(bitmap) ((bitmap)->chunksize >> BITMAP_BLOCK_SHIFT)
+#define CHUNK_BLOCK_SHIFT(bitmap) ((bitmap)->chunkshift - BITMAP_BLOCK_SHIFT)
+#define CHUNK_BLOCK_MASK(bitmap) (CHUNK_BLOCK_RATIO(bitmap) - 1)
+
+/* when hijacked, the counters and bits represent even larger "chunks" */
+/* there will be 1024 chunks represented by each counter in the page pointers */
+#define PAGEPTR_BLOCK_RATIO(bitmap) \
+			(CHUNK_BLOCK_RATIO(bitmap) << PAGE_COUNTER_SHIFT >> 1)
+#define PAGEPTR_BLOCK_SHIFT(bitmap) \
+			(CHUNK_BLOCK_SHIFT(bitmap) + PAGE_COUNTER_SHIFT - 1)
+#define PAGEPTR_BLOCK_MASK(bitmap) (PAGEPTR_BLOCK_RATIO(bitmap) - 1)
+
+/*
+ * on-disk bitmap:
+ *
+ * Use one bit per "chunk" (block set). We do the disk I/O on the bitmap
+ * file a page at a time. There's a superblock at the start of the file.
+ */
+
+/* map chunks (bits) to file pages - offset by the size of the superblock */
+#define CHUNK_BIT_OFFSET(chunk) ((chunk) + (sizeof(bitmap_super_t) << 3))
+
+#endif
+
+/*
+ * bitmap structures:
+ */
+
+#define BITMAP_MAGIC 0x6d746962
+
+/* use these for bitmap->flags and bitmap->sb->state bit-fields */
+enum bitmap_state {
+	BITMAP_ACTIVE = 0x001, /* the bitmap is in use */
+	BITMAP_STALE  = 0x002  /* the bitmap file is out of date or had -EIO */
+};
+
+/* the superblock at the front of the bitmap file -- little endian */
+typedef struct bitmap_super_s {
+	__u32 magic;        /*  0  BITMAP_MAGIC */
+	__u32 version;      /*  4  the bitmap major for now, could change... */
+	__u8  uuid[16];     /*  8  128 bit uuid - must match md device uuid */
+	__u64 events;       /* 24  event counter for the bitmap (1)*/
+	__u64 events_cleared;/*32  event counter when last bit cleared (2) */
+	__u64 sync_size;    /* 40  the size of the md device's sync range(3) */
+	__u32 state;        /* 48  bitmap state information */
+	__u32 chunksize;    /* 52  the bitmap chunk size in bytes */
+	__u32 daemon_sleep; /* 56  seconds between disk flushes */
+	__u32 write_behind; /* 60  number of outstanding write-behind writes */
+
+	__u8  pad[256 - 64]; /* set to zero */
+} bitmap_super_t;
+
+/* notes:
+ * (1) This event counter is updated before the eventcounter in the md superblock
+ *    When a bitmap is loaded, it is only accepted if this event counter is equal
+ *    to, or one greater than, the event counter in the superblock.
+ * (2) This event counter is updated when the other one is *if*and*only*if* the 
+ *    array is not degraded.  As bits are not cleared when the array is degraded,
+ *    this represents the last time that any bits were cleared.
+ *    If a device is being added that has an event count with this value or
+ *    higher, it is accepted as conforming to the bitmap.
+ * (3)This is the number of sectors represented by the bitmap, and is the range that
+ *    resync happens across.  For raid1 and raid5/6 it is the size of individual
+ *    devices.  For raid10 it is the size of the array.
+ */
+
+#ifdef __KERNEL__
+
+/* the in-memory bitmap is represented by bitmap_pages */
+struct bitmap_page {
+	/*
+	 * map points to the actual memory page
+	 */
+	char *map;
+	/*
+	 * in emergencies (when map cannot be alloced), hijack the map
+	 * pointer and use it as two counters itself
+	 */
+	unsigned int hijacked;
+	/*
+	 * count of dirty bits on the page
+	 */ 
+	int count;
+};
+
+/* keep track of bitmap file pages that have pending writes on them */
+struct page_list {
+	struct list_head list;
+	struct page *page;
+};
+
+/* the main bitmap structure - one per mddev */
+struct bitmap {
+	struct bitmap_page *bp;
+	unsigned long pages; /* total number of pages in the bitmap */
+	unsigned long missing_pages; /* number of pages not yet allocated */
+
+	mddev_t *mddev; /* the md device that the bitmap is for */
+
+	int counter_bits; /* how many bits per block counter */
+
+	/* bitmap chunksize -- how much data does each bit represent? */
+	unsigned long chunksize;
+	unsigned long chunkshift; /* chunksize = 2^chunkshift (for bitops) */
+	unsigned long chunks; /* total number of data chunks for the array */
+
+	/* We hold a count on the chunk currently being synced, and drop
+	 * it when the last block is started.  If the resync is aborted
+	 * midway, we need to be able to drop that count, so we remember
+	 * the counted chunk..
+	 */
+	unsigned long syncchunk;
+
+	__u64	events_cleared;
+
+	/* bitmap spinlock */
+	spinlock_t lock;
+
+	struct file *file; /* backing disk file */
+	struct page *sb_page; /* cached copy of the bitmap file superblock */
+	struct page **filemap; /* list of cache pages for the file */
+	unsigned long *filemap_attr; /* attributes associated w/ filemap pages */
+	unsigned long file_pages; /* number of pages in the file */
+
+	unsigned long flags;
+
+	/*
+	 * the bitmap daemon - periodically wakes up and sweeps the bitmap
+	 * file, cleaning up bits and flushing out pages to disk as necessary
+	 */
+	mdk_thread_t *daemon;
+	unsigned long daemon_sleep; /* how many seconds between updates? */
+
+	/*
+	 * bitmap write daemon - this daemon performs writes to the bitmap file
+	 * this thread is only needed because of a limitation in ext3 (jbd)
+	 * that does not allow a task to have two journal transactions ongoing
+	 * simultaneously (even if the transactions are for two different
+	 * filesystems) -- in the case of bitmap, that would be the filesystem
+	 * that the bitmap file resides on and the filesystem that is mounted
+	 * on the md device -- see current->journal_info in jbd/transaction.c
+	 */
+	mdk_thread_t *write_daemon;
+	mdk_thread_t *writeback_daemon;
+	spinlock_t write_lock;
+	struct semaphore write_ready;
+	struct semaphore write_done;
+	unsigned long writes_pending;
+	wait_queue_head_t write_wait;
+	struct list_head write_pages;
+	struct list_head complete_pages;
+	mempool_t *write_pool;
+};
+
+/* the bitmap API */
+
+/* these are used only by md/bitmap */
+int  bitmap_create(mddev_t *mddev);
+void bitmap_destroy(mddev_t *mddev);
+int  bitmap_active(struct bitmap *bitmap);
+
+char *file_path(struct file *file, char *buf, int count);
+void bitmap_print_sb(struct bitmap *bitmap);
+int bitmap_update_sb(struct bitmap *bitmap);
+
+int  bitmap_setallbits(struct bitmap *bitmap);
+
+/* these are exported */
+void bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sectors);
+void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long sectors,
+		     int success);
+int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks);
+void bitmap_end_sync(struct bitmap *bitmap, sector_t offset, int *blocks, int aborted);
+void bitmap_close_sync(struct bitmap *bitmap);
+
+int bitmap_unplug(struct bitmap *bitmap);
+#endif
+
+#endif
diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/mdadm/config.c busybox-1.7.4+gentoo+mdadm/mdadm/config.c
--- busybox-1.7.4+gentoo/mdadm/config.c	1969-12-31 16:00:00.000000000 -0800
+++ busybox-1.7.4+gentoo+mdadm/mdadm/config.c	2008-03-11 10:31:00.000000000 -0700
@@ -0,0 +1,824 @@
+/*
+ * mdadm - manage Linux "md" devices aka RAID arrays.
+ *
+ * Copyright (C) 2001-2006 Neil Brown <neilb@suse.de>
+ *
+ *
+ *    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
+ *
+ *    Author: Neil Brown
+ *    Email: <neilb@cse.unsw.edu.au>
+ *    Paper: Neil Brown
+ *           School of Computer Science and Engineering
+ *           The University of New South Wales
+ *           Sydney, 2052
+ *           Australia
+ */
+
+#include	"mdadm.h"
+#include	"dlink.h"
+#include	<sys/dir.h>
+#include	<glob.h>
+#include	<fnmatch.h>
+#include	<ctype.h>
+#include	<pwd.h>
+#include	<grp.h>
+
+mapping_t r5layout[] = {
+	{ "left-asymmetric", 0},
+	{ "right-asymmetric", 1},
+	{ "left-symmetric", 2},
+	{ "right-symmetric", 3},
+
+	{ "default", 2},
+	{ "la", 0},
+	{ "ra", 1},
+	{ "ls", 2},
+	{ "rs", 3},
+	{ NULL, 0}
+};
+
+mapping_t pers[] = {
+	{ "linear", -1},
+	{ "raid0", 0},
+	{ "0", 0},
+	{ "stripe", 0},
+	{ "raid1", 1},
+	{ "1", 1},
+	{ "mirror", 1},
+	{ "raid4", 4},
+	{ "4", 4},
+	{ "raid5", 5},
+	{ "5", 5},
+	{ "multipath", -4},
+	{ "mp", -4},
+	{ "raid6", 6},
+	{ "6", 6},
+	{ "raid10", 10},
+	{ "10", 10},
+	{ "faulty", -5},
+	{ NULL, 0}
+};
+/*
+ * Read the config file
+ *
+ * conf_get_uuids gets a list of devicename+uuid pairs
+ * conf_get_devs gets device names after expanding wildcards
+ *
+ * Each keeps the returned list and frees it when asked to make
+ * a new list.
+ *
+ * The format of the config file needs to be fairly extensible.
+ * Now, arrays only have names and uuids and devices merely are.
+ * But later arrays might want names, and devices might want superblock
+ * versions, and who knows what else.
+ * I like free format, abhore backslash line continuation, adore
+ *   indentation for structure and am ok about # comments.
+ *
+ * So, each line that isn't blank or a #comment must either start
+ *  with a key word, and not be indented, or must start with a
+ *  non-key-word and must be indented.
+ *
+ * Keywords are DEVICE and ARRAY
+ * DEV{ICE} introduces some devices that might contain raid components.
+ * e.g.
+ *   DEV style=0 /dev/sda* /dev/hd*
+ *   DEV style=1 /dev/sd[b-f]*
+ * ARR{AY} describes an array giving md device and attributes like uuid=whatever
+ * e.g.
+ *   ARRAY /dev/md0 uuid=whatever name=something
+ * Spaces separate words on each line.  Quoting, with "" or '' protects them,
+ * but may not wrap over lines
+ *
+ */
+
+#ifndef CONFFILE
+#define CONFFILE "/etc/mdadm.conf"
+#endif
+#ifndef CONFFILE2
+/* for Debian compatibility .... */
+#define CONFFILE2 "/etc/mdadm/mdadm.conf"
+#endif
+char DefaultConfFile[] = CONFFILE;
+char DefaultAltConfFile[] = CONFFILE2;
+
+enum linetype { Devices, Array, Mailaddr, Mailfrom, Program, CreateDev, Homehost, LTEnd };
+char *keywords[] = {
+	[Devices]  = "devices",
+	[Array]    = "array",
+	[Mailaddr] = "mailaddr",
+	[Mailfrom] = "mailfrom",
+	[Program]  = "program",
+	[CreateDev]= "create",
+	[Homehost] = "homehost",
+	[LTEnd]    = NULL
+};
+
+/*
+ * match_keyword returns an index into the keywords array, or -1 for no match
+ * case is ignored, and at least three characters must be given
+ */
+
+int match_keyword(char *word)
+{
+	int len = strlen(word);
+	int n;
+    
+	if (len < 3) return -1;
+	for (n=0; keywords[n]; n++) {
+		if (strncasecmp(word, keywords[n], len)==0)
+			return n;
+	}
+	return -1;
+}
+
+/* conf_word gets one word from the conf file.
+ * if "allow_key", then accept words at the start of a line,
+ * otherwise stop when such a word is found.
+ * We assume that the file pointer is at the end of a word, so the
+ * next character is a space, or a newline.  If not, it is the start of a line.
+ */
+
+char *conf_word(FILE *file, int allow_key)
+{
+	int wsize = 100;
+	int len = 0;
+	int c;
+	int quote;
+	int wordfound = 0;
+	char *word = malloc(wsize);
+
+	if (!word) abort();
+
+	while (wordfound==0) {
+		/* at the end of a word.. */
+		c = getc(file);
+		if (c == '#')
+			while (c != EOF && c != '\n')
+				c = getc(file);
+		if (c == EOF) break;
+		if (c == '\n') continue;
+
+		if (c != ' ' && c != '\t' && ! allow_key) {
+			ungetc(c, file);
+			break;
+		}
+		/* looks like it is safe to get a word here, if there is one */
+		quote = 0;
+		/* first, skip any spaces */
+		while (c == ' ' || c == '\t')
+			c = getc(file);
+		if (c != EOF && c != '\n' && c != '#') {
+			/* we really have a character of a word, so start saving it */
+			while (c != EOF && c != '\n' && (quote || (c!=' ' && c != '\t'))) {
+				wordfound = 1;
+				if (quote && c == quote) quote = 0;
+				else if (quote == 0 && (c == '\'' || c == '"'))
+					quote = c;
+				else {
+					if (len == wsize-1) {
+						wsize += 100;
+						word = realloc(word, wsize);
+						if (!word) abort();
+					}
+					word[len++] = c;
+				}
+				c = getc(file);
+			}
+		}
+		if (c != EOF) ungetc(c, file);
+	}
+	word[len] = 0;
+/*    printf("word is <%s>\n", word); */
+	if (!wordfound) {
+		free(word);
+		word = NULL;
+	}
+	return word;
+}
+	
+/*
+ * conf_line reads one logical line from the conffile.
+ * It skips comments and continues until it finds a line that starts
+ * with a non blank/comment.  This character is pushed back for the next call
+ * A doubly linked list of words is returned.
+ * the first word will be a keyword.  Other words will have had quotes removed.
+ */
+
+char *conf_line(FILE *file)
+{
+	char *w;
+	char *list;
+
+	w = conf_word(file, 1);
+	if (w == NULL) return NULL;
+
+	list = dl_strdup(w);
+	free(w);
+	dl_init(list);
+
+	while ((w = conf_word(file,0))){
+		char *w2 = dl_strdup(w);
+		free(w);
+		dl_add(list, w2);
+	}
+/*    printf("got a line\n");*/
+	return list;
+}
+
+void free_line(char *line)
+{
+	char *w;
+	for (w=dl_next(line); w != line; w=dl_next(line)) {
+		dl_del(w);
+		dl_free(w);
+	}
+	dl_free(line);
+}
+
+
+struct conf_dev {
+    struct conf_dev *next;
+    char *name;
+} *cdevlist = NULL;
+
+mddev_dev_t load_partitions(void)
+{
+	FILE *f = fopen("/proc/partitions", "r");
+	char buf[1024];
+	mddev_dev_t rv = NULL;
+	if (f == NULL) {
+		fprintf(stderr, Name ": cannot open /proc/partitions\n");
+		return NULL;
+	}
+	while (fgets(buf, 1024, f)) {
+		int major, minor;
+		char *name, *mp;
+		mddev_dev_t d;
+
+		buf[1023] = '\0';
+		if (buf[0] != ' ')
+			continue;
+		major = strtoul(buf, &mp, 10);
+		if (mp == buf || *mp != ' ') 
+			continue;
+		minor = strtoul(mp, NULL, 10);
+
+		name = map_dev(major, minor, 1);
+		if (!name)
+			continue;
+		d = malloc(sizeof(*d));
+		d->devname = strdup(name);
+		d->next = rv;
+		d->used = 0;
+		rv = d;
+	}
+	fclose(f);
+	return rv;
+}
+
+struct createinfo createinfo = {
+	.autof = 2, /* by default, create devices with standard names */
+	.symlinks = 1,
+#ifdef DEBIAN
+	.gid = 6, /* disk */
+	.mode = 0660,
+#else
+	.mode = 0600,
+#endif
+};
+
+int parse_auto(char *str, char *msg, int config)
+{
+	int autof;
+	if (str == NULL || *str == 0)
+		autof = 2;
+	else if (strcasecmp(str,"no")==0)
+		autof = 1;
+	else if (strcasecmp(str,"yes")==0)
+		autof = 2;
+	else if (strcasecmp(str,"md")==0)
+		autof = config?5:3;
+	else {
+		/* There might be digits, and maybe a hypen, at the end */
+		char *e = str + strlen(str);
+		int num = 4;
+		int len;
+		while (e > str && isdigit(e[-1]))
+			e--;
+		if (*e) {
+			num = atoi(e);
+			if (num <= 0) num = 1;
+		}
+		if (e > str && e[-1] == '-')
+			e--;
+		len = e - str;
+		if ((len == 2 && strncasecmp(str,"md",2)==0)) {
+			autof = config ? 5 : 3;
+		} else if ((len == 3 && strncasecmp(str,"yes",3)==0)) {
+			autof = 2;
+		} else if ((len == 3 && strncasecmp(str,"mdp",3)==0)) {
+			autof = config ? 6 : 4;
+		} else if ((len == 1 && strncasecmp(str,"p",1)==0) ||
+			   (len >= 4 && strncasecmp(str,"part",4)==0)) {
+			autof = 6;
+		} else {
+			fprintf(stderr, Name ": %s arg of \"%s\" unrecognised: use no,yes,md,mdp,part\n"
+				"        optionally followed by a number.\n",
+				msg, str);
+			exit(2);
+		}
+		autof |= num << 3;
+	}
+	return autof;
+}
+
+static void createline(char *line)
+{
+	char *w;
+	char *ep;
+
+	for (w=dl_next(line); w!=line; w=dl_next(w)) {
+		if (strncasecmp(w, "auto=", 5) == 0)
+			createinfo.autof = parse_auto(w+5, "auto=", 1);
+		else if (strncasecmp(w, "owner=", 6) == 0) {
+			if (w[6] == 0) {
+				fprintf(stderr, Name ": missing owner name\n");
+				continue;
+			}
+			createinfo.uid = strtoul(w+6, &ep, 10);
+			if (*ep != 0) {
+				struct passwd *pw;
+				/* must be a name */
+				pw = getpwnam(w+6);
+				if (pw)
+					createinfo.uid = pw->pw_uid;
+				else
+					fprintf(stderr, Name ": CREATE user %s not found\n", w+6);
+			}
+		} else if (strncasecmp(w, "group=", 6) == 0) {
+			if (w[6] == 0) {
+				fprintf(stderr, Name ": missing group name\n");
+				continue;
+			}
+			createinfo.gid = strtoul(w+6, &ep, 10);
+			if (*ep != 0) {
+				struct group *gr;
+				/* must be a name */
+				gr = getgrnam(w+6);
+				if (gr)
+					createinfo.gid = gr->gr_gid;
+				else
+					fprintf(stderr, Name ": CREATE group %s not found\n", w+6);
+			}
+		} else if (strncasecmp(w, "mode=", 5) == 0) {
+			if (w[5] == 0) {
+				fprintf(stderr, Name ": missing CREATE mode\n");
+				continue;
+			}
+			createinfo.mode = strtoul(w+5, &ep, 8);
+			if (*ep != 0) {
+				createinfo.mode = 0600;
+				fprintf(stderr, Name ": unrecognised CREATE mode %s\n",
+					w+5);
+			}
+		} else if (strncasecmp(w, "metadata=", 9) == 0) {
+			/* style of metadata to use by default */
+			int i;
+			for (i=0; superlist[i] && !createinfo.supertype; i++)
+				createinfo.supertype =
+					superlist[i]->match_metadata_desc(w+9);
+			if (!createinfo.supertype)
+				fprintf(stderr, Name ": metadata format %s unknown, ignoring\n",
+					w+9);
+		} else if (strncasecmp(w, "symlinks=yes", 12) == 0)
+			createinfo.symlinks = 1;
+		else if  (strncasecmp(w, "symlinks=no", 11) == 0)
+			createinfo.symlinks = 0;
+		else {
+			fprintf(stderr, Name ": unrecognised word on CREATE line: %s\n",
+				w);
+		}
+	}
+}
+
+void devline(char *line) 
+{
+	char *w;
+	struct conf_dev *cd;
+
+	for (w=dl_next(line); w != line; w=dl_next(w)) {
+		if (w[0] == '/' || strcasecmp(w, "partitions") == 0) {
+			cd = malloc(sizeof(*cd));
+			cd->name = strdup(w);
+			cd->next = cdevlist;
+			cdevlist = cd;
+		} else {
+			fprintf(stderr, Name ": unreconised word on DEVICE line: %s\n",
+				w);
+		}
+	}
+}
+
+mddev_ident_t mddevlist = NULL;
+mddev_ident_t *mddevlp = &mddevlist;
+
+void arrayline(char *line)
+{
+	char *w;
+
+	struct mddev_ident_s mis;
+	mddev_ident_t mi;
+
+	mis.uuid_set = 0;
+	mis.super_minor = UnSet;
+	mis.level = UnSet;
+	mis.raid_disks = UnSet;
+	mis.spare_disks = 0;
+	mis.devices = NULL;
+	mis.devname = NULL;
+	mis.spare_group = NULL;
+	mis.autof = 0;
+	mis.next = NULL;
+	mis.st = NULL;
+	mis.bitmap_fd = -1;
+	mis.bitmap_file = NULL;
+	mis.name[0] = 0;
+
+	for (w=dl_next(line); w!=line; w=dl_next(w)) {
+		if (w[0] == '/') {
+			if (mis.devname)
+				fprintf(stderr, Name ": only give one device per ARRAY line: %s and %s\n",
+					mis.devname, w);
+			else mis.devname = w;
+		} else if (strncasecmp(w, "uuid=", 5)==0 ) {
+			if (mis.uuid_set)
+				fprintf(stderr, Name ": only specify uuid once, %s ignored.\n",
+					w);
+			else {
+				if (parse_uuid(w+5, mis.uuid))
+					mis.uuid_set = 1;
+				else
+					fprintf(stderr, Name ": bad uuid: %s\n", w);
+			}
+		} else if (strncasecmp(w, "super-minor=", 12)==0 ) {
+			if (mis.super_minor != UnSet)
+				fprintf(stderr, Name ": only specify super-minor once, %s ignored.\n",
+					w);
+			else {
+				char *endptr;
+				mis.super_minor= strtol(w+12, &endptr, 10);
+				if (w[12]==0 || endptr[0]!=0 || mis.super_minor < 0) {
+					fprintf(stderr, Name ": invalid super-minor number: %s\n",
+						w);
+					mis.super_minor = UnSet;
+				}
+			}
+		} else if (strncasecmp(w, "name=", 5)==0) {
+			if (mis.name[0])
+				fprintf(stderr, Name ": only specify name once, %s ignored.\n",
+					w);
+			else if (strlen(w+5) > 32)
+				fprintf(stderr, Name ": name too long, ignoring %s\n", w);
+			else
+				strcpy(mis.name, w+5);
+
+		} else if (strncasecmp(w, "bitmap=", 7) == 0) {
+			if (mis.bitmap_file)
+				fprintf(stderr, Name ": only specify bitmap file once. %s ignored\n",
+					w);
+			else
+				mis.bitmap_file = strdup(w+7);
+
+		} else if (strncasecmp(w, "devices=", 8 ) == 0 ) {
+			if (mis.devices)
+				fprintf(stderr, Name ": only specify devices once (use a comma separated list). %s ignored\n",
+					w);
+			else
+				mis.devices = strdup(w+8);
+		} else if (strncasecmp(w, "spare-group=", 12) == 0 ) {
+			if (mis.spare_group)
+				fprintf(stderr, Name ": only specify one spare group per array. %s ignored.\n",
+					w);
+			else
+				mis.spare_group = strdup(w+12);
+		} else if (strncasecmp(w, "level=", 6) == 0 ) {
+			/* this is mainly for compatability with --brief output */
+			mis.level = map_name(pers, w+6);
+		} else if (strncasecmp(w, "disks=", 6) == 0 ) {
+			/* again, for compat */
+			mis.raid_disks = atoi(w+6);
+		} else if (strncasecmp(w, "num-devices=", 12) == 0 ) {
+			/* again, for compat */
+			mis.raid_disks = atoi(w+12);
+		} else if (strncasecmp(w, "spares=", 7) == 0 ) {
+			/* for warning if not all spares present */
+			mis.spare_disks = atoi(w+7);
+		} else if (strncasecmp(w, "metadata=", 9) == 0) {
+			/* style of metadata on the devices. */
+			int i;
+			
+			for(i=0; superlist[i] && !mis.st; i++)
+				mis.st = superlist[i]->match_metadata_desc(w+9);
+
+			if (!mis.st)
+				fprintf(stderr, Name ": metadata format %s unknown, ignored.\n", w+9);
+		} else if (strncasecmp(w, "auto=", 5) == 0 ) {
+			/* whether to create device special files as needed */
+			mis.autof = parse_auto(w+5, "auto type", 0);
+		} else {
+			fprintf(stderr, Name ": unrecognised word on ARRAY line: %s\n",
+				w);
+		}
+	}
+	if (mis.devname == NULL)
+		fprintf(stderr, Name ": ARRAY line with no device\n");
+	else if (mis.uuid_set == 0 && mis.devices == NULL && mis.super_minor == UnSet && mis.name[0] == 0)
+		fprintf(stderr, Name ": ARRAY line %s has no identity information.\n", mis.devname);
+	else {
+		mi = malloc(sizeof(*mi));
+		*mi = mis;
+		mi->devname = strdup(mis.devname);
+		mi->next = NULL;
+		*mddevlp = mi;
+		mddevlp = &mi->next;
+	}
+}
+
+static char *alert_email = NULL;
+void mailline(char *line)
+{
+	char *w;
+
+	for (w=dl_next(line); w != line ; w=dl_next(w)) {
+		if (alert_email == NULL)
+			alert_email = strdup(w);
+		else
+			fprintf(stderr, Name ": excess address on MAIL line: %s - ignored\n",
+				w);
+	}
+}
+
+static char *alert_mail_from = NULL;
+void mailfromline(char *line)
+{
+	char *w;
+
+	for (w=dl_next(line); w != line ; w=dl_next(w)) {
+		if (alert_mail_from == NULL)
+			alert_mail_from = strdup(w);
+		else {
+			char *t= NULL;
+			asprintf(&t, "%s %s", alert_mail_from, w);
+			free(alert_mail_from);
+			alert_mail_from = t;
+		}
+	}
+}
+
+
+static char *alert_program = NULL;
+void programline(char *line)
+{
+	char *w;
+
+	for (w=dl_next(line); w != line ; w=dl_next(w)) {
+		if (alert_program == NULL)
+			alert_program = strdup(w);
+		else
+			fprintf(stderr, Name ": excess program on PROGRAM line: %s - ignored\n",
+				w);
+	}
+}
+
+static char *home_host = NULL;
+void homehostline(char *line)
+{
+	char *w;
+
+	for (w=dl_next(line); w != line ; w=dl_next(w)) {
+		if (home_host == NULL)
+			home_host = strdup(w);
+		else
+			fprintf(stderr, Name ": excess host name on HOMEHOST line: %s - ignored\n",
+				w);
+	}
+}
+
+
+int loaded = 0;
+
+static char *conffile = NULL;
+void set_conffile(char *file)
+{
+	conffile = file;
+}
+
+void load_conffile(void)
+{
+	FILE *f;
+	char *line;
+
+	if (loaded) return;
+	if (conffile == NULL)
+		conffile = DefaultConfFile;
+
+	if (strcmp(conffile, "none") == 0) {
+		loaded = 1;
+		return;
+	}
+	if (strcmp(conffile, "partitions")==0) {
+		char *list = dl_strdup("DEV");
+		dl_init(list);
+		dl_add(list, dl_strdup("partitions"));
+		devline(list);
+		free_line(list);
+		loaded = 1;
+		return;
+	}
+	f = fopen(conffile, "r");
+	/* Debian chose to relocate mdadm.conf into /etc/mdadm/.
+	 * To allow Debian users to compile from clean source and still
+	 * have a working mdadm, we read /etc/mdadm/mdadm.conf
+	 * if /etc/mdadm.conf doesn't exist
+	 */
+	if (f == NULL &&
+	    conffile == DefaultConfFile) {
+		f = fopen(DefaultAltConfFile, "r");
+		if (f)
+			conffile = DefaultAltConfFile;
+	}
+	if (f == NULL)
+		return;
+
+	loaded = 1;
+	while ((line=conf_line(f))) {
+		switch(match_keyword(line)) {
+		case Devices:
+			devline(line);
+			break;
+		case Array:
+			arrayline(line);
+			break;
+		case Mailaddr:
+			mailline(line);
+			break;
+		case Mailfrom:
+			mailfromline(line);
+			break;
+		case Program:
+			programline(line);
+			break;
+		case CreateDev:
+			createline(line);
+			break;
+		case Homehost:
+			homehostline(line);
+			break;
+		default:
+			fprintf(stderr, Name ": Unknown keyword %s\n", line);
+		}
+		free_line(line);
+	}
+    
+	fclose(f);
+
+/*    printf("got file\n"); */
+}
+
+char *conf_get_mailaddr(void)
+{
+	load_conffile();
+	return alert_email;
+}
+
+char *conf_get_mailfrom(void)
+{
+	load_conffile();
+	return alert_mail_from;
+}
+
+char *conf_get_program(void)
+{
+	load_conffile();
+	return alert_program;
+}
+
+char *conf_get_homehost(void)
+{
+	load_conffile();
+	return home_host;
+}
+
+struct createinfo *conf_get_create_info(void)
+{
+	load_conffile();
+	return &createinfo;
+}
+
+mddev_ident_t conf_get_ident(char *dev)
+{
+	mddev_ident_t rv;
+	load_conffile();
+	rv = mddevlist;
+	while (dev && rv && strcmp(dev, rv->devname)!=0)
+		rv = rv->next;
+	return rv;
+}
+
+mddev_dev_t conf_get_devs()
+{
+	glob_t globbuf;
+	struct conf_dev *cd;
+	int flags = 0;
+	static mddev_dev_t dlist = NULL;
+	unsigned int i;
+
+	while (dlist) {
+		mddev_dev_t t = dlist;
+		dlist = dlist->next;
+		free(t->devname);
+		free(t);
+	}
+    
+	load_conffile();
+
+	if (cdevlist == NULL)
+		/* default to 'partitions */
+		dlist = load_partitions();
+
+	for (cd=cdevlist; cd; cd=cd->next) {
+		if (strcasecmp(cd->name, "partitions")==0 && dlist == NULL)
+			dlist = load_partitions();
+		else {
+			glob(cd->name, flags, NULL, &globbuf);
+			flags |= GLOB_APPEND;
+		}
+	}
+	if (flags & GLOB_APPEND) {
+		for (i=0; i<globbuf.gl_pathc; i++) {
+			mddev_dev_t t = malloc(sizeof(*t));
+			t->devname = strdup(globbuf.gl_pathv[i]);
+			t->next = dlist;
+			t->used = 0;
+			dlist = t;
+/*	printf("one dev is %s\n", t->devname);*/
+		}
+		globfree(&globbuf);
+	}
+
+	return dlist;
+}
+
+int conf_test_dev(char *devname)
+{
+	struct conf_dev *cd;
+	if (cdevlist == NULL)
+		/* allow anything by default */
+		return 1;
+	for (cd = cdevlist ; cd ; cd = cd->next) {
+		if (strcasecmp(cd->name, "partitions") == 0)
+			return 1;
+		if (fnmatch(cd->name, devname, FNM_PATHNAME) == 0)
+			return 1;
+	}
+	return 0;
+}
+
+
+int match_oneof(char *devices, char *devname)
+{
+    /* check if one of the comma separated patterns in devices
+     * matches devname
+     */
+
+
+    while (devices && *devices) {
+	char patn[1024];
+	char *p = devices;
+	devices = strchr(devices, ',');
+	if (!devices)
+	    devices = p + strlen(p);
+	if (devices-p < 1024) {
+		strncpy(patn, p, devices-p);
+		patn[devices-p] = 0;
+		if (fnmatch(patn, devname, FNM_PATHNAME)==0)
+			return 1;
+	}
+	if (*devices == ',')
+		devices++;
+    }
+    return 0;
+}
diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/mdadm/Config.in busybox-1.7.4+gentoo+mdadm/mdadm/Config.in
--- busybox-1.7.4+gentoo/mdadm/Config.in	1969-12-31 16:00:00.000000000 -0800
+++ busybox-1.7.4+gentoo+mdadm/mdadm/Config.in	2008-03-11 10:31:00.000000000 -0700
@@ -0,0 +1,15 @@
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "Linux mdadm Utilities"
+
+config MDADM
+	bool "mdadm"
+	default n
+	help
+	  assemble or examine raid array
+
+endmenu
+
diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/mdadm/dlink.c busybox-1.7.4+gentoo+mdadm/mdadm/dlink.c
--- busybox-1.7.4+gentoo/mdadm/dlink.c	1969-12-31 16:00:00.000000000 -0800
+++ busybox-1.7.4+gentoo+mdadm/mdadm/dlink.c	2008-03-11 10:31:00.000000000 -0700
@@ -0,0 +1,79 @@
+
+/* doubly linked lists */
+/* This is free software. No strings attached. No copyright claimed */
+
+#include	<unistd.h>
+#include	<stdlib.h>
+#include	<string.h>
+#ifdef __dietlibc__
+char *strncpy(char *dest, const char *src, size_t n) __THROW;
+#endif
+#include	"dlink.h"
+
+
+void *dl_head()
+{
+    void *h;
+    h = dl_alloc(0);
+    dl_next(h) = h;
+    dl_prev(h) = h;
+    return h;
+}
+
+void dl_free(void *v)
+{
+    struct __dl_head *vv  = v;
+    free(vv-1);
+}
+
+void dl_init(void *v)
+{
+    dl_next(v) = v;
+    dl_prev(v) = v;
+}
+
+void dl_insert(void *head, void *val)
+{
+    dl_next(val) = dl_next(head);
+    dl_prev(val) = head;
+    dl_next(dl_prev(val)) = val;
+    dl_prev(dl_next(val)) = val;
+}
+
+void dl_add(void *head, void *val)
+{
+    dl_prev(val) = dl_prev(head);
+    dl_next(val) = head;
+    dl_next(dl_prev(val)) = val;
+    dl_prev(dl_next(val)) = val;
+}
+
+void dl_del(void *val)
+{
+    if (dl_prev(val) == 0 || dl_next(val) == 0)
+	return;
+    dl_prev(dl_next(val)) = dl_prev(val);
+    dl_next(dl_prev(val)) = dl_next(val);
+    dl_prev(val) = dl_next(val) = 0;
+}
+
+char *dl_strndup(char *s, int l)
+{
+    char *n;
+    if (s == NULL)
+	return NULL;
+    n = dl_newv(char, l+1);
+    if (n == NULL)
+	return NULL;
+    else
+    {
+	strncpy(n, s, l);
+	n[l] = 0;
+	return n;
+    }
+}
+
+char *dl_strdup(char *s)
+{
+    return dl_strndup(s, (int)strlen(s));
+}
diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/mdadm/dlink.h busybox-1.7.4+gentoo+mdadm/mdadm/dlink.h
--- busybox-1.7.4+gentoo/mdadm/dlink.h	1969-12-31 16:00:00.000000000 -0800
+++ busybox-1.7.4+gentoo+mdadm/mdadm/dlink.h	2008-03-11 10:31:00.000000000 -0700
@@ -0,0 +1,25 @@
+
+/* doubley linked lists */
+/* This is free software. No strings attached. No copyright claimed */
+
+struct __dl_head
+{
+    void * dh_prev;
+    void * dh_next;
+};
+
+#define	dl_alloc(size)	((void*)(((char*)calloc(1,(size)+sizeof(struct __dl_head)))+sizeof(struct __dl_head)))
+#define	dl_new(t)	((t*)dl_alloc(sizeof(t)))
+#define	dl_newv(t,n)	((t*)dl_alloc(sizeof(t)*n))
+
+#define dl_next(p) *(&(((struct __dl_head*)(p))[-1].dh_next))
+#define dl_prev(p) *(&(((struct __dl_head*)(p))[-1].dh_prev))
+
+void *dl_head(void);
+char *dl_strdup(char *);
+char *dl_strndup(char *, int);
+void dl_insert(void*, void*);
+void dl_add(void*, void*);
+void dl_del(void*);
+void dl_free(void*);
+void dl_init(void*);
diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/mdadm/md5.h busybox-1.7.4+gentoo+mdadm/mdadm/md5.h
--- busybox-1.7.4+gentoo/mdadm/md5.h	1969-12-31 16:00:00.000000000 -0800
+++ busybox-1.7.4+gentoo+mdadm/mdadm/md5.h	2008-03-11 10:31:00.000000000 -0700
@@ -0,0 +1,134 @@
+/* Declaration of functions and data types used for MD5 sum computing
+   library functions.
+   Copyright (C) 1995-1997,1999-2005 Free Software Foundation, Inc.
+
+   NOTE: The canonical source of this file is maintained with the GNU C
+   Library.  Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any
+   later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#ifndef _MD5_H
+#define _MD5_H 1
+
+#include <stdio.h>
+
+# include <inttypes.h>
+#if HAVE_STDINT_H || _LIBC
+# include <stdint.h>
+#endif
+
+#ifndef __GNUC_PREREQ
+# if defined __GNUC__ && defined __GNUC_MINOR__
+#  define __GNUC_PREREQ(maj, min) \
+	((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
+# else
+#  define __GNUC_PREREQ(maj, min) 0
+# endif
+#endif
+
+#ifndef __THROW
+# if defined __cplusplus && __GNUC_PREREQ (2,8)
+#  define __THROW	throw ()
+# else
+#  define __THROW
+# endif
+#endif
+
+#ifndef __attribute__
+# if ! __GNUC_PREREQ (2,8) || __STRICT_ANSI__
+#  define __attribute__(x)
+# endif
+#endif
+
+#ifndef _LIBC
+# define __md5_buffer md5_buffer
+# define __md5_finish_ctx md5_finish_ctx
+# define __md5_init_ctx md5_init_ctx
+# define __md5_process_block md5_process_block
+# define __md5_process_bytes md5_process_bytes
+# define __md5_read_ctx md5_read_ctx
+# define __md5_stream md5_stream
+#endif
+
+typedef uint32_t md5_uint32;
+
+/* Structure to save state of computation between the single steps.  */
+struct md5_ctx
+{
+  md5_uint32 A;
+  md5_uint32 B;
+  md5_uint32 C;
+  md5_uint32 D;
+
+  md5_uint32 total[2];
+  md5_uint32 buflen;
+  char buffer[128] __attribute__ ((__aligned__ (__alignof__ (md5_uint32))));
+};
+
+/*
+ * The following three functions are build up the low level used in
+ * the functions `md5_stream' and `md5_buffer'.
+ */
+
+/* Initialize structure containing state of computation.
+   (RFC 1321, 3.3: Step 3)  */
+extern void __md5_init_ctx (struct md5_ctx *ctx) __THROW;
+
+/* Starting with the result of former calls of this function (or the
+   initialization function update the context for the next LEN bytes
+   starting at BUFFER.
+   It is necessary that LEN is a multiple of 64!!! */
+extern void __md5_process_block (const void *buffer, size_t len,
+				 struct md5_ctx *ctx) __THROW;
+
+/* Starting with the result of former calls of this function (or the
+   initialization function update the context for the next LEN bytes
+   starting at BUFFER.
+   It is NOT required that LEN is a multiple of 64.  */
+extern void __md5_process_bytes (const void *buffer, size_t len,
+				 struct md5_ctx *ctx) __THROW;
+
+/* Process the remaining bytes in the buffer and put result from CTX
+   in first 16 bytes following RESBUF.  The result is always in little
+   endian byte order, so that a byte-wise output yields to the wanted
+   ASCII representation of the message digest.
+
+   IMPORTANT: On some systems it is required that RESBUF be correctly
+   aligned for a 32 bits value.  */
+extern void *__md5_finish_ctx (struct md5_ctx *ctx, void *resbuf) __THROW;
+
+
+/* Put result from CTX in first 16 bytes following RESBUF.  The result is
+   always in little endian byte order, so that a byte-wise output yields
+   to the wanted ASCII representation of the message digest.
+
+   IMPORTANT: On some systems it is required that RESBUF is correctly
+   aligned for a 32 bits value.  */
+extern void *__md5_read_ctx (const struct md5_ctx *ctx, void *resbuf) __THROW;
+
+
+/* Compute MD5 message digest for bytes read from STREAM.  The
+   resulting message digest number will be written into the 16 bytes
+   beginning at RESBLOCK.  */
+extern int __md5_stream (FILE *stream, void *resblock) __THROW;
+
+/* Compute MD5 message digest for LEN bytes beginning at BUFFER.  The
+   result is always in little endian byte order, so that a byte-wise
+   output yields to the wanted ASCII representation of the message
+   digest.  */
+extern void *__md5_buffer (const char *buffer, size_t len,
+			   void *resblock) __THROW;
+
+#endif /* md5.h */
diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/mdadm/mdadm.c busybox-1.7.4+gentoo+mdadm/mdadm/mdadm.c
--- busybox-1.7.4+gentoo/mdadm/mdadm.c	1969-12-31 16:00:00.000000000 -0800
+++ busybox-1.7.4+gentoo+mdadm/mdadm/mdadm.c	2008-03-11 10:31:00.000000000 -0700
@@ -0,0 +1,18 @@
+/*
+ * mdadm support for busybox.
+ * added by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+#include <string.h>
+
+extern int mdassemble_main(int argc, char **argv);
+extern int mdexamine_main(int argc, char **argv);
+
+int mdadm_main(int argc, char **argv) {
+	if (argc >= 2) {
+		if (!strncmp(argv[1],"--assemble",10))
+			return mdassemble_main(argc, argv);
+		if (!strncmp(argv[1],"--examine",9))
+			return mdexamine_main(argc, argv);
+	}
+	return 0;
+}
diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/mdadm/mdadm.h busybox-1.7.4+gentoo+mdadm/mdadm/mdadm.h
--- busybox-1.7.4+gentoo/mdadm/mdadm.h	1969-12-31 16:00:00.000000000 -0800
+++ busybox-1.7.4+gentoo+mdadm/mdadm/mdadm.h	2008-03-11 10:31:00.000000000 -0700
@@ -0,0 +1,540 @@
+/*
+ * mdadm - manage Linux "md" devices aka RAID arrays.
+ *
+ * Copyright (C) 2001-2006 Neil Brown <neilb@suse.de>
+ *
+ *
+ *    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
+ *
+ *    Author: Neil Brown
+ *    Email: <neilb@cse.unsw.edu.au>
+ *    Paper: Neil Brown
+ *           School of Computer Science and Engineering
+ *           The University of New South Wales
+ *           Sydney, 2052
+ *           Australia
+ */
+
+#include	<unistd.h>
+#ifndef __dietlibc__
+extern __off64_t lseek64 __P ((int __fd, __off64_t __offset, int __whence));
+#else
+# if defined(__NO_STAT64) || __WORDSIZE != 32
+# define lseek64 lseek
+# endif
+#endif
+
+#include	<sys/types.h>
+#include	<sys/stat.h>
+#include	<stdlib.h>
+#include	<time.h>
+#include	<sys/time.h>
+#include	<getopt.h>
+#include	<fcntl.h>
+#include	<stdio.h>
+#include	<errno.h>
+#include	<string.h>
+#include	<syslog.h>
+#ifdef __dietlibc__
+#include	<strings.h>
+/* dietlibc has deprecated random and srandom!! */
+#define random rand
+#define srandom srand
+#endif
+
+
+#include	<linux/kdev_t.h>
+/*#include	<linux/fs.h> */
+#include	<sys/mount.h>
+#include	<asm/types.h>
+#include	<sys/ioctl.h>
+#define	MD_MAJOR 9
+#define MdpMinorShift 6
+
+#ifndef BLKGETSIZE64
+#define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size in bytes (u64 *arg) */
+#endif
+
+#define DEFAULT_BITMAP_CHUNK 4096
+#define DEFAULT_BITMAP_DELAY 5
+#define DEFAULT_MAX_WRITE_BEHIND 256
+
+#include	"md_u.h"
+#include	"md_p.h"
+#include	"bitmap.h"
+
+#include <endian.h>
+/* Redhat don't like to #include <asm/byteorder.h>, and
+ * some time include <linux/byteorder/xxx_endian.h> isn't enough,
+ * and there is no standard conversion function so... */
+/* And dietlibc doesn't think byteswap is ok, so.. */
+/*  #include <byteswap.h> */
+#define bswap_16(x) (((x) & 0x00ffU) << 8 | \
+		     ((x) & 0xff00U) >> 8)
+#define bswap_32(x) (((x) & 0x000000ffU) << 24 | \
+		     ((x) & 0xff000000U) >> 24 | \
+		     ((x) & 0x0000ff00U) << 8  | \
+		     ((x) & 0x00ff0000U) >> 8)
+#define bswap_64(x) (((x) & 0x00000000000000ffULL) << 56 | \
+		     ((x) & 0xff00000000000000ULL) >> 56 | \
+		     ((x) & 0x000000000000ff00ULL) << 40 | \
+		     ((x) & 0x00ff000000000000ULL) >> 40 | \
+		     ((x) & 0x0000000000ff0000ULL) << 24 | \
+		     ((x) & 0x0000ff0000000000ULL) >> 24 | \
+		     ((x) & 0x00000000ff000000ULL) << 8 | \
+		     ((x) & 0x000000ff00000000ULL) >> 8)
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define	__cpu_to_le16(_x) (_x)
+#define __cpu_to_le32(_x) (_x)
+#define __cpu_to_le64(_x) (_x)
+#define	__le16_to_cpu(_x) (_x)
+#define __le32_to_cpu(_x) (_x)
+#define __le64_to_cpu(_x) (_x)
+#elif BYTE_ORDER == BIG_ENDIAN
+#define	__cpu_to_le16(_x) bswap_16(_x)
+#define __cpu_to_le32(_x) bswap_32(_x)
+#define __cpu_to_le64(_x) bswap_64(_x)
+#define	__le16_to_cpu(_x) bswap_16(_x)
+#define __le32_to_cpu(_x) bswap_32(_x)
+#define __le64_to_cpu(_x) bswap_64(_x)
+#else
+#  error "unknown endianness."
+#endif
+
+
+
+/* general information that might be extracted from a superblock */
+struct mdinfo {
+	mdu_array_info_t	array;
+	mdu_disk_info_t		disk;
+	__u64			events;
+	int			uuid[4];
+	char			name[33];
+	unsigned long long	data_offset;
+	unsigned long long	component_size;
+	int			reshape_active;
+	unsigned long long	reshape_progress;
+	int			new_level, delta_disks, new_layout, new_chunk;
+};
+
+struct createinfo {
+	int	uid;
+	int	gid;
+	int	autof;
+	int	mode;
+	int	symlinks;
+	struct supertype *supertype;
+};
+
+#define Name "mdadm"
+
+enum mode {
+	ASSEMBLE=1,
+	BUILD,
+	CREATE,
+	MANAGE,
+	MISC,
+	MONITOR,
+	GROW,
+	INCREMENTAL,
+	AUTODETECT,
+};
+
+extern char short_options[];
+extern char short_bitmap_auto_options[];
+extern struct option long_options[];
+extern char Version[], Usage[], Help[], OptionHelp[],
+	Help_create[], Help_build[], Help_assemble[], Help_grow[],
+	Help_incr[],
+	Help_manage[], Help_misc[], Help_monitor[], Help_config[];
+
+/* for option that don't have short equivilents, we assign arbitrary
+ * small numbers.  '1' means an undecorated option, so we start at '2'.
+ */
+enum special_options {
+	AssumeClean = 2,
+	BitmapChunk,
+	WriteBehind,
+	ReAdd,
+	NoDegraded,
+	Sparc22,
+	BackupFile,
+	HomeHost,
+	AutoHomeHost,
+	Symlinks,
+	AutoDetect,
+};
+
+/* structures read from config file */
+/* List of mddevice names and identifiers
+ * Identifiers can be:
+ *    uuid=128-hex-uuid
+ *    super-minor=decimal-minor-number-from-superblock
+ *    devices=comma,separated,list,of,device,names,with,wildcards
+ *
+ * If multiple fields are present, the intersection of all matching
+ * devices is considered
+ */
+#define UnSet (0xfffe)
+typedef struct mddev_ident_s {
+	char	*devname;
+	
+	int	uuid_set;
+	int	uuid[4];
+	char	name[33];
+
+	unsigned int super_minor;
+
+	char	*devices;	/* comma separated list of device
+				 * names with wild cards
+				 */
+	int	level;
+	unsigned int raid_disks;
+	unsigned int spare_disks;
+	struct supertype *st;
+	int	autof;		/* 1 for normal, 2 for partitioned */
+	char	*spare_group;
+	char	*bitmap_file;
+	int	bitmap_fd;
+
+	struct mddev_ident_s *next;
+} *mddev_ident_t;
+
+/* List of device names - wildcards expanded */
+typedef struct mddev_dev_s {
+	char *devname;
+	char disposition;	/* 'a' for add, 'r' for remove, 'f' for fail.
+				 * Not set for names read from .config
+				 */
+	char writemostly;
+	char re_add;
+	char used;		/* set when used */
+	struct mddev_dev_s *next;
+} *mddev_dev_t;
+
+typedef struct mapping {
+	char *name;
+	int num;
+} mapping_t;
+
+
+struct mdstat_ent {
+	char		*dev;
+	int		devnum;
+	int		active;
+	char		*level;
+	char		*pattern; /* U or up, _ for down */
+	int		percent; /* -1 if no resync */
+	int		resync; /* 1 if resync, 0 if recovery */
+	struct mdstat_ent *next;
+};
+
+extern struct mdstat_ent *mdstat_read(int hold, int start);
+extern void free_mdstat(struct mdstat_ent *ms);
+extern void mdstat_wait(int seconds);
+extern int mddev_busy(int devnum);
+
+struct map_ent {
+	struct map_ent *next;
+	int	devnum;
+	int	major,minor;
+	int	uuid[4];
+	char	*path;
+};
+extern int map_update(struct map_ent **mpp, int devnum, int major, int minor,
+		      int uuid[4], char *path);
+extern struct map_ent *map_by_uuid(struct map_ent **map, int uuid[4]);
+extern void map_read(struct map_ent **melp);
+extern int map_write(struct map_ent *mel);
+extern void map_delete(struct map_ent **mapp, int devnum);
+extern void map_free(struct map_ent *map);
+extern void map_add(struct map_ent **melp,
+		    int devnum, int major, int minor, int uuid[4], char *path);
+
+/* Data structure for holding info read from sysfs */
+struct sysdev {
+	char	name[20];
+	int	role;
+	int	major, minor;
+	unsigned long long offset, size;
+	int	state;
+	int	errors;
+	struct sysdev *next;
+};
+struct sysarray {
+	char	name[20];
+	struct sysdev *devs;
+	int	chunk;
+	unsigned long long component_size;
+	int	layout;
+	int	level;
+	int	spares;
+	int	cache_size;
+	int	mismatch_cnt;
+	int	major_version, minor_version;
+};
+/* various details can be requested */
+#define	GET_LEVEL	1
+#define	GET_LAYOUT	2
+#define	GET_COMPONENT	4
+#define	GET_CHUNK	8
+#define GET_CACHE	16
+#define	GET_MISMATCH	32
+#define	GET_VERSION	64
+
+#define	GET_DEVS	1024 /* gets role, major, minor */
+#define	GET_OFFSET	2048
+#define	GET_SIZE	4096
+#define	GET_STATE	8192
+#define	GET_ERROR	16384
+
+/* If fd >= 0, get the array it is open on,
+ * else use devnum. >=0 -> major9. <0.....
+ */
+extern void sysfs_free(struct sysarray *sra);
+extern struct sysarray *sysfs_read(int fd, int devnum, unsigned long options);
+extern int sysfs_set_str(struct sysarray *sra, struct sysdev *dev,
+			 char *name, char *val);
+extern int sysfs_set_num(struct sysarray *sra, struct sysdev *dev,
+			 char *name, unsigned long long val);
+extern int sysfs_get_ll(struct sysarray *sra, struct sysdev *dev,
+			char *name, unsigned long long *val);
+
+
+extern int save_stripes(int *source, unsigned long long *offsets,
+			int raid_disks, int chunk_size, int level, int layout,
+			int nwrites, int *dest,
+			unsigned long long start, unsigned long long length);
+extern int restore_stripes(int *dest, unsigned long long *offsets,
+			   int raid_disks, int chunk_size, int level, int layout,
+			   int source, unsigned long long read_offset,
+			   unsigned long long start, unsigned long long length);
+
+#ifndef Sendmail
+#define Sendmail "/usr/lib/sendmail -t"
+#endif
+
+#define SYSLOG_FACILITY LOG_DAEMON
+
+extern char *map_num(mapping_t *map, int num);
+extern int map_name(mapping_t *map, char *name);
+extern mapping_t r5layout[], pers[], modes[], faultylayout[];
+
+extern char *map_dev(int major, int minor, int create);
+
+
+extern struct superswitch {
+	void (*examine_super)(void *sbv, char *homehost);
+	void (*brief_examine_super)(void *sbv);
+	void (*detail_super)(void *sbv, char *homehost);
+	void (*export_super)(void *sbv);
+	void (*brief_detail_super)(void *sbv);
+	void (*uuid_from_super)(int uuid[4], void *sbv);
+	void (*getinfo_super)(struct mdinfo *info, void *sbv);
+	int (*match_home)(void *sbv, char *homehost);
+	int (*update_super)(struct mdinfo *info, void *sbv, char *update,
+			    char *devname, int verbose,
+			    int uuid_set, char *homehost);
+	int (*init_super)(struct supertype *st, void **sbp, mdu_array_info_t *info, unsigned long long size, char *name, char *homehost, int *uuid);
+	void (*add_to_super)(void *sbv, mdu_disk_info_t *dinfo);
+	int (*store_super)(struct supertype *st, int fd, void *sbv);
+	int (*write_init_super)(struct supertype *st, void *sbv, mdu_disk_info_t *dinfo, char *devname);
+	int (*compare_super)(void **firstp, void *secondv);
+	int (*load_super)(struct supertype *st, int fd, void **sbp, char *devname);
+	struct supertype * (*match_metadata_desc)(char *arg);
+	__u64 (*avail_size)(struct supertype *st, __u64 size);
+	int (*add_internal_bitmap)(struct supertype *st, void *sbv, int *chunkp,
+				   int delay, int write_behind,
+				   unsigned long long size, int may_change, int major);
+	void (*locate_bitmap)(struct supertype *st, int fd, void *sbv);
+	int (*write_bitmap)(struct supertype *st, int fd, void *sbv);
+	int major;
+	int swapuuid; /* true if uuid is bigending rather than hostendian */
+} super0, super1, *superlist[];
+
+struct supertype {
+	struct superswitch *ss;
+	int minor_version;
+	int max_devs;
+};
+
+extern struct supertype *super_by_version(int vers, int minor);
+extern struct supertype *guess_super(int fd);
+extern int get_dev_size(int fd, char *dname, unsigned long long *sizep);
+extern void get_one_disk(int mdfd, mdu_array_info_t *ainf,
+			 mdu_disk_info_t *disk);
+
+#if __GNUC__ < 3
+struct stat64;
+#endif
+
+#define HAVE_NFTW  we assume
+#define HAVE_FTW
+
+#ifdef UCLIBC
+# include <features.h>
+# ifndef  __UCLIBC_HAS_FTW__
+#  undef HAVE_FTW
+#  undef HAVE_NFTW
+# endif
+#endif
+
+#ifdef __dietlibc__
+# undef HAVE_NFTW
+#endif
+
+#ifndef HAVE_NFTW
+# define FTW_PHYS 1
+# ifndef HAVE_FTW
+  struct FTW {};
+# endif
+#endif
+
+#ifdef HAVE_FTW
+# include <ftw.h>
+#endif
+
+extern int add_dev(const char *name, const struct stat *stb, int flag, struct FTW *s);
+
+
+extern int Manage_ro(char *devname, int fd, int readonly);
+extern int Manage_runstop(char *devname, int fd, int runstop, int quiet);
+extern int Manage_resize(char *devname, int fd, long long size, int raid_disks);
+extern int Manage_reconfig(char *devname, int fd, int layout);
+extern int Manage_subdevs(char *devname, int fd,
+			  mddev_dev_t devlist, int verbose);
+extern int autodetect(void);
+extern int Grow_Add_device(char *devname, int fd, char *newdev);
+extern int Grow_addbitmap(char *devname, int fd, char *file, int chunk, int delay, int write_behind, int force);
+extern int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
+			long long size,
+			int level, int layout, int chunksize, int raid_disks);
+extern int Grow_restart(struct supertype *st, struct mdinfo *info,
+			int *fdlist, int cnt, char *backup_file);
+
+
+extern int Assemble(struct supertype *st, char *mddev, int mdfd,
+		    mddev_ident_t ident,
+		    mddev_dev_t devlist, char *backup_file,
+		    int readonly, int runstop,
+		    char *update, char *homehost,
+		    int verbose, int force);
+
+extern int Build(char *mddev, int mdfd, int chunk, int level, int layout,
+		 int raiddisks,
+		 mddev_dev_t devlist, int assume_clean,
+		 char *bitmap_file, int bitmap_chunk, int write_behind, int delay, int verbose);
+
+
+extern int Create(struct supertype *st, char *mddev, int mdfd,
+		  int chunk, int level, int layout, unsigned long long size, int raiddisks, int sparedisks,
+		  char *name, char *homehost, int *uuid,
+		  int subdevs, mddev_dev_t devlist,
+		  int runstop, int verbose, int force, int assume_clean,
+		  char *bitmap_file, int bitmap_chunk, int write_behind, int delay);
+
+extern int Detail(char *dev, int brief, int export, int test, char *homehost);
+extern int Query(char *dev);
+
+extern int md_get_version(int fd);
+extern int get_linux_version(void);
+extern int parse_uuid(char *str, int uuid[4]);
+extern int check_ext2(int fd, char *name);
+extern int check_reiser(int fd, char *name);
+extern int check_raid(int fd, char *name);
+
+extern int get_mdp_major(void);
+extern int dev_open(char *dev, int flags);
+extern int is_standard(char *dev, int *nump);
+
+extern int parse_auto(char *str, char *msg, int config);
+extern mddev_ident_t conf_get_ident(char *dev);
+extern mddev_dev_t conf_get_devs(void);
+extern int conf_test_dev(char *devname);
+extern struct createinfo *conf_get_create_info(void);
+extern void set_conffile(char *file);
+extern char *conf_get_mailaddr(void);
+extern char *conf_get_mailfrom(void);
+extern char *conf_get_program(void);
+extern char *conf_get_homehost(void);
+extern char *conf_line(FILE *file);
+extern char *conf_word(FILE *file, int allow_key);
+extern void free_line(char *line);
+extern int match_oneof(char *devices, char *devname);
+extern void uuid_from_super(int uuid[4], mdp_super_t *super);
+extern int same_uuid(int a[4], int b[4], int swapuuid);
+extern void copy_uuid(void *a, int b[4], int swapuuid);
+/* extern int compare_super(mdp_super_t *first, mdp_super_t *second);*/
+extern unsigned long calc_csum(void *super, int bytes);
+extern int enough(int level, int raid_disks, int layout, int clean,
+		   char *avail, int avail_disks);
+extern int ask(char *mesg);
+extern unsigned long long get_component_size(int fd);
+extern void remove_partitions(int fd);
+
+
+extern char *human_size(long long bytes);
+char *human_size_brief(long long bytes);
+
+extern void put_md_name(char *name);
+extern char *get_md_name(int dev);
+
+extern char DefaultConfFile[];
+
+extern int open_mddev(char *dev, int autof);
+extern int open_mddev_devnum(char *devname, int devnum, char *name,
+			     char *chosen_name);
+
+
+#define	LEVEL_MULTIPATH		(-4)
+#define	LEVEL_LINEAR		(-1)
+#define	LEVEL_FAULTY		(-5)
+
+
+/* faulty stuff */
+
+#define	WriteTransient	0
+#define	ReadTransient	1
+#define	WritePersistent	2
+#define	ReadPersistent	3
+#define	WriteAll	4 /* doesn't go to device */
+#define	ReadFixable	5
+#define	Modes	6
+
+#define	ClearErrors	31
+#define	ClearFaults	30
+
+#define AllPersist	100 /* internal use only */
+#define	NoPersist	101
+
+#define	ModeMask	0x1f
+#define	ModeShift	5
+
+
+#ifdef __TINYC__
+#undef minor
+#undef major
+#undef makedev
+#define minor(x) ((x)&0xff)
+#define major(x) (((x)>>8)&0xff)
+#define makedev(M,m) (((M)<<8) | (m))
+#endif
+
+/* for raid5 */
+#define ALGORITHM_LEFT_ASYMMETRIC	0
+#define ALGORITHM_RIGHT_ASYMMETRIC	1
+#define ALGORITHM_LEFT_SYMMETRIC	2
+#define ALGORITHM_RIGHT_SYMMETRIC	3
diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/mdadm/mdassemble.c busybox-1.7.4+gentoo+mdadm/mdadm/mdassemble.c
--- busybox-1.7.4+gentoo/mdadm/mdassemble.c	1969-12-31 16:00:00.000000000 -0800
+++ busybox-1.7.4+gentoo+mdadm/mdadm/mdassemble.c	2008-03-11 10:31:00.000000000 -0700
@@ -0,0 +1,908 @@
+/*
+ * mdadm - manage Linux "md" devices aka RAID arrays.
+ *
+ * Copyright (C) 2001-2006 Neil Brown <neilb@suse.de>
+ *
+ *
+ *    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
+ *
+ *    Author: Neil Brown
+ *    Email: <neilb@cse.unsw.edu.au>
+ *    Paper: Neil Brown
+ *           School of Computer Science and Engineering
+ *           The University of New South Wales
+ *           Sydney, 2052
+ *           Australia
+ */
+
+#include	"mdadm.h"
+#include	<ctype.h>
+
+static int name_matches(char *found, char *required, char *homehost)
+{
+	/* See if the name found matches the required name, possibly
+	 * prefixed with 'homehost'
+	 */
+	char fnd[33];
+
+	strncpy(fnd, found, 32);
+	fnd[32] = 0;
+	if (strcmp(found, required)==0)
+		return 1;
+	if (homehost) {
+		int l = strlen(homehost);
+		if (l < 32 && fnd[l] == ':' &&
+		    strcmp(fnd+l+1, required)==0)
+			return 1;
+	}
+	return 0;
+}
+
+int open_mddev(char *dev, int autof/*unused */)
+{
+	int mdfd = open(dev, O_RDWR, 0);
+	if (mdfd < 0)
+		fprintf(stderr, Name ": error opening %s: %s\n",
+			dev, strerror(errno));
+	else if (md_get_version(mdfd) <= 0) {
+		fprintf(stderr, Name ": %s does not appear to be an md device\n",
+			dev);
+		close(mdfd);
+		mdfd = -1;
+	}
+	return mdfd;
+}
+
+int Assemble(struct supertype *st, char *mddev, int mdfd,
+	     mddev_ident_t ident,
+	     mddev_dev_t devlist, char *backup_file,
+	     int readonly, int runstop,
+	     char *update, char *homehost,
+	     int verbose, int force)
+{
+	/*
+	 * The task of Assemble is to find a collection of
+	 * devices that should (according to their superblocks)
+	 * form an array, and to give this collection to the MD driver.
+	 * In Linux-2.4 and later, this involves submitting a
+	 * SET_ARRAY_INFO ioctl with no arg - to prepare
+	 * the array - and then submit a number of
+	 * ADD_NEW_DISK ioctls to add disks into
+	 * the array.  Finally RUN_ARRAY might
+	 * be submitted to start the array.
+	 *
+	 * Much of the work of Assemble is in finding and/or
+	 * checking the disks to make sure they look right.
+	 *
+	 * If mddev is not set, then scan must be set and we
+	 *  read through the config file for dev+uuid mapping
+	 *  We recurse, setting mddev, for each device that
+	 *    - isn't running
+	 *    - has a valid uuid (or any uuid if !uuidset)
+	 *
+	 * If mddev is set, we try to determine state of md.
+	 *   check version - must be at least 0.90.0
+	 *   check kernel version.  must be at least 2.4.
+	 *    If not, we can possibly fall back on START_ARRAY
+	 *   Try to GET_ARRAY_INFO.
+	 *     If possible, give up
+	 *     If not, try to STOP_ARRAY just to make sure
+	 *
+	 * If !uuidset and scan, look in conf-file for uuid
+	 *       If not found, give up
+	 * If !devlist and scan and uuidset, get list of devs from conf-file
+	 *
+	 * For each device:
+	 *   Check superblock - discard if bad
+	 *   Check uuid (set if we don't have one) - discard if no match
+	 *   Check superblock similarity if we have a superblock - discard if different
+	 *   Record events, devicenum
+	 * This should give us a list of devices for the array
+	 * We should collect the most recent event number
+	 *
+	 * Count disks with recent enough event count
+	 * While force && !enough disks
+	 *    Choose newest rejected disks, update event count
+	 *     mark clean and rewrite superblock
+	 * If recent kernel:
+	 *    SET_ARRAY_INFO
+	 *    foreach device with recent events : ADD_NEW_DISK
+	 *    if runstop == 1 || "enough" disks and runstop==0 -> RUN_ARRAY
+	 * If old kernel:
+	 *    Check the device numbers in superblock are right
+	 *    update superblock if any changes
+	 *    START_ARRAY
+	 *
+	 */
+	int clean = 0;
+	int old_linux = 0;
+	int vers = 0; /* Keep gcc quite - it really is initialised */
+	void *first_super = NULL, *super = NULL;
+	struct {
+		char *devname;
+		unsigned int major, minor;
+		unsigned int oldmajor, oldminor;
+		long long events;
+		int uptodate;
+		int state;
+		int raid_disk;
+		int disk_nr;
+	} *devices;
+	int *best = NULL; /* indexed by raid_disk */
+	unsigned int bestcnt = 0;
+	int devcnt = 0;
+	unsigned int okcnt, sparecnt;
+	unsigned int req_cnt;
+	unsigned int i;
+	int most_recent = 0;
+	int chosen_drive;
+	int change = 0;
+	int inargv = 0;
+	int bitmap_done;
+	int start_partial_ok = (runstop >= 0) && (force || devlist==NULL || mdfd < 0);
+	unsigned int num_devs;
+	mddev_dev_t tmpdev;
+	struct mdinfo info;
+	char *avail;
+	int nextspare = 0;
+
+	if (mdfd < 0)
+		return 2;
+
+	if (get_linux_version() < 2004000)
+		old_linux = 1;
+
+	if (mdfd >= 0) {
+		vers = md_get_version(mdfd);
+		if (vers <= 0) {
+			fprintf(stderr, Name ": %s appears not to be an md device.\n", mddev);
+			return 1;
+		}
+		if (vers < 9000) {
+			fprintf(stderr, Name ": Assemble requires driver version 0.90.0 or later.\n"
+				"    Upgrade your kernel or try --build\n");
+			return 1;
+		}
+
+		if (ioctl(mdfd, GET_ARRAY_INFO, &info.array)>=0) {
+			fprintf(stderr, Name ": device %s already active - cannot assemble it\n",
+				mddev);
+			return 1;
+		}
+		ioctl(mdfd, STOP_ARRAY, NULL); /* just incase it was started but has no content */
+	}
+	/*
+	 * If any subdevs are listed, then any that don't
+	 * match ident are discarded.  Remainder must all match and
+	 * become the array.
+	 * If no subdevs, then we scan all devices in the config file, but
+	 * there must be something in the identity
+	 */
+
+	if (!devlist &&
+	    ident->uuid_set == 0 &&
+	    ident->super_minor < 0 &&
+	    ident->devices == NULL) {
+		fprintf(stderr, Name ": No identity information available for %s - cannot assemble.\n",
+			mddev ? mddev : "further assembly");
+		return 1;
+	}
+	if (devlist == NULL)
+		devlist = conf_get_devs();
+	else if (mdfd >= 0)
+		inargv = 1;
+
+	tmpdev = devlist; num_devs = 0;
+	while (tmpdev) {
+		if (tmpdev->used)
+			tmpdev->used = 2;
+		else
+			num_devs++;
+		tmpdev = tmpdev->next;
+	}
+	devices = malloc(num_devs * sizeof(*devices));
+
+	if (!st && ident->st) st = ident->st;
+
+	if (verbose>0)
+	    fprintf(stderr, Name ": looking for devices for %s\n",
+		    mddev ? mddev : "further assembly");
+
+	/* first walk the list of devices to find a consistent set
+	 * that match the criterea, if that is possible.
+	 * We flag the one we like with 'used'.
+	 */
+	for (tmpdev = devlist;
+	     tmpdev;
+	     tmpdev = tmpdev->next) {
+		char *devname = tmpdev->devname;
+		int dfd;
+		struct stat stb;
+		struct supertype *tst = st;
+
+		if (tmpdev->used > 1) continue;
+
+		if (ident->devices &&
+		    !match_oneof(ident->devices, devname)) {
+			if ((inargv && verbose>=0) || verbose > 0)
+				fprintf(stderr, Name ": %s is not one of %s\n", devname, ident->devices);
+			continue;
+		}
+
+		if (super) {
+			free(super);
+			super = NULL;
+		}
+		
+		dfd = dev_open(devname, O_RDONLY|O_EXCL);
+		if (dfd < 0) {
+			if ((inargv && verbose >= 0) || verbose > 0)
+				fprintf(stderr, Name ": cannot open device %s: %s\n",
+					devname, strerror(errno));
+			tmpdev->used = 2;
+		} else if (fstat(dfd, &stb)< 0) {
+			/* Impossible! */
+			fprintf(stderr, Name ": fstat failed for %s: %s\n",
+				devname, strerror(errno));
+			tmpdev->used = 2;
+		} else if ((stb.st_mode & S_IFMT) != S_IFBLK) {
+			fprintf(stderr, Name ": %s is not a block device.\n",
+				devname);
+			tmpdev->used = 2;
+		} else if (!tst && (tst = guess_super(dfd)) == NULL) {
+			if ((inargv && verbose >= 0) || verbose > 0)
+				fprintf(stderr, Name ": no recogniseable superblock on %s\n",
+					devname);
+			tmpdev->used = 2;
+		} else if (tst->ss->load_super(tst,dfd, &super, NULL)) {
+			if ((inargv && verbose >= 0) || verbose > 0)
+				fprintf( stderr, Name ": no RAID superblock on %s\n",
+					 devname);
+		} else {
+			tst->ss->getinfo_super(&info, super);
+		}
+		if (dfd >= 0) close(dfd);
+
+		if (ident->uuid_set && (!update || strcmp(update, "uuid")!= 0) &&
+		    (!super || same_uuid(info.uuid, ident->uuid, tst->ss->swapuuid)==0)) {
+			if ((inargv && verbose >= 0) || verbose > 0)
+				fprintf(stderr, Name ": %s has wrong uuid.\n",
+					devname);
+			continue;
+		}
+		if (ident->name[0] && (!update || strcmp(update, "name")!= 0) &&
+		    (!super || name_matches(info.name, ident->name, homehost)==0)) {
+			if ((inargv && verbose >= 0) || verbose > 0)
+				fprintf(stderr, Name ": %s has wrong name.\n",
+					devname);
+			continue;
+		}
+		if (ident->super_minor != UnSet &&
+		    (!super || ident->super_minor != info.array.md_minor)) {
+			if ((inargv && verbose >= 0) || verbose > 0)
+				fprintf(stderr, Name ": %s has wrong super-minor.\n",
+					devname);
+			continue;
+		}
+		if (ident->level != UnSet &&
+		    (!super|| ident->level != info.array.level)) {
+			if ((inargv && verbose >= 0) || verbose > 0)
+				fprintf(stderr, Name ": %s has wrong raid level.\n",
+					devname);
+			continue;
+		}
+		if (ident->raid_disks != UnSet &&
+		    (!super || ident->raid_disks!= info.array.raid_disks)) {
+			if ((inargv && verbose >= 0) || verbose > 0)
+				fprintf(stderr, Name ": %s requires wrong number of drives.\n",
+					devname);
+			continue;
+		}
+		if (mdfd < 0) {
+			if (tst == NULL || super == NULL)
+				continue;
+			if (update == NULL &&
+			    tst->ss->match_home(super, homehost)==0) {
+				if ((inargv && verbose >= 0) || verbose > 0)
+					fprintf(stderr, Name ": %s is not built for host %s.\n",
+						devname, homehost);
+				/* Auto-assemble, and this is not a usable host */
+				/* if update != NULL, we are updating the host
+				 * name... */
+				continue;
+			}
+		}
+		/* If we are this far, then we are nearly commited to this device.
+		 * If the super_block doesn't exist, or doesn't match others,
+		 * then we probably cannot continue
+		 * However if one of the arrays is for the homehost, and
+		 * the other isn't that can disambiguate.
+		 */
+
+		if (!super) {
+			fprintf(stderr, Name ": %s has no superblock - assembly aborted\n",
+				devname);
+			free(first_super);
+			return 1;
+		}
+
+		if (st == NULL)
+			st = tst;
+		if (st->ss != tst->ss ||
+		    st->minor_version != tst->minor_version ||
+		    st->ss->compare_super(&first_super, super) != 0) {
+			/* Some mismatch. If exactly one array matches this host,
+			 * we can resolve on that one.
+			 * Or, if we are auto assembling, we just ignore the second
+			 * for now.
+			 */
+			if (mdfd < 0)
+				continue;
+			if (homehost) {
+				int first = st->ss->match_home(first_super, homehost);
+				int last = tst->ss->match_home(super, homehost);
+				if (first+last == 1) {
+					/* We can do something */
+					if (first) {/* just ignore this one */
+						if ((inargv && verbose >= 0) || verbose > 0)
+							fprintf(stderr, Name ": %s misses out due to wrong homehost\n",
+								devname);
+						continue;
+					} else { /* reject all those sofar */
+						mddev_dev_t td;
+						if ((inargv && verbose >= 0) || verbose > 0)
+							fprintf(stderr, Name ": %s overrides previous devices due to good homehost\n",
+								devname);
+						for (td=devlist; td != tmpdev; td=td->next)
+							if (td->used == 1)
+								td->used = 0;
+						tmpdev->used = 1;
+						continue;
+					}
+				}
+			}
+			fprintf(stderr, Name ": superblock on %s doesn't match others - assembly aborted\n",
+				devname);
+			free(super);
+			free(first_super);
+			return 1;
+		}
+
+		tmpdev->used = 1;
+	}
+
+	/* Ok, no bad inconsistancy, we can try updating etc */
+	bitmap_done = 0;
+	for (tmpdev = devlist; tmpdev; tmpdev=tmpdev->next) if (tmpdev->used == 1) {
+		char *devname = tmpdev->devname;
+		struct stat stb;
+		/* looks like a good enough match to update the super block if needed */
+		{
+			int dfd;
+			dfd = dev_open(devname, O_RDWR|O_EXCL);
+
+			remove_partitions(dfd);
+
+			if (super) {
+				free(super);
+				super = NULL;
+			}
+
+			st->ss->load_super(st, dfd, &super, NULL);
+			st->ss->getinfo_super(&info, super);
+			close(dfd);
+		}
+
+		stat(devname, &stb);
+
+		if (verbose > 0)
+			fprintf(stderr, Name ": %s is identified as a member of %s, slot %d.\n",
+				devname, mddev, info.disk.raid_disk);
+		devices[devcnt].devname = devname;
+		devices[devcnt].major = major(stb.st_rdev);
+		devices[devcnt].minor = minor(stb.st_rdev);
+		devices[devcnt].oldmajor = info.disk.major;
+		devices[devcnt].oldminor = info.disk.minor;
+		devices[devcnt].events = info.events;
+		devices[devcnt].raid_disk = info.disk.raid_disk;
+		devices[devcnt].disk_nr = info.disk.number;
+		devices[devcnt].uptodate = 0;
+		devices[devcnt].state = info.disk.state;
+		if (most_recent < devcnt) {
+			if (devices[devcnt].events
+			    > devices[most_recent].events)
+				most_recent = devcnt;
+		}
+		if (info.array.level == -4)
+			/* with multipath, the raid_disk from the superblock is meaningless */
+			i = devcnt;
+		else
+			i = devices[devcnt].raid_disk;
+		if (i+1 == 0) {
+			if (nextspare < info.array.raid_disks)
+				nextspare = info.array.raid_disks;
+			i = nextspare++;
+		} else {
+			if (i >= info.array.raid_disks &&
+			    i >= nextspare)
+				nextspare = i+1;
+		}
+		if (i < 10000) {
+			if (i >= bestcnt) {
+				unsigned int newbestcnt = i+10;
+				int *newbest = malloc(sizeof(int)*newbestcnt);
+				unsigned int c;
+				for (c=0; c < newbestcnt; c++)
+					if (c < bestcnt)
+						newbest[c] = best[c];
+					else
+						newbest[c] = -1;
+				if (best)free(best);
+				best = newbest;
+				bestcnt = newbestcnt;
+			}
+			if (best[i] >=0 &&
+			    devices[best[i]].events == devices[devcnt].events &&
+			    devices[best[i]].minor != devices[devcnt].minor &&
+			    st->ss->major == 0 &&
+			    info.array.level != -4) {
+				/* two different devices with identical superblock.
+				 * Could be a mis-detection caused by overlapping
+				 * partitions.  fail-safe.
+				 */
+				fprintf(stderr, Name ": WARNING %s and %s appear"
+					" to have very similar superblocks.\n"
+					"      If they are really different, "
+					"please --zero the superblock on one\n"
+					"      If they are the same or overlap,"
+					" please remove one from %s.\n",
+					devices[best[i]].devname, devname,
+					inargv ? "the list" :
+					   "the\n      DEVICE list in mdadm.conf"
+					);
+				return 1;
+			}
+			if (best[i] == -1
+			    || devices[best[i]].events < devices[devcnt].events)
+				best[i] = devcnt;
+		}
+		devcnt++;
+	}
+
+	if (super)
+		free(super);
+	super = NULL;
+
+	if (update && strcmp(update, "byteorder")==0)
+		st->minor_version = 90;
+
+	if (devcnt == 0) {
+		fprintf(stderr, Name ": no devices found for %s\n",
+			mddev);
+		free(first_super);
+		return 1;
+	}
+
+	st->ss->getinfo_super(&info, first_super);
+	clean = info.array.state & 1;
+
+	/* now we have some devices that might be suitable.
+	 * I wonder how many
+	 */
+	avail = malloc(info.array.raid_disks);
+	memset(avail, 0, info.array.raid_disks);
+	okcnt = 0;
+	sparecnt=0;
+	for (i=0; i< bestcnt ;i++) {
+		int j = best[i];
+		int event_margin = 1; /* always allow a difference of '1'
+				       * like the kernel does
+				       */
+		if (j < 0) continue;
+		/* note: we ignore error flags in multipath arrays
+		 * as they don't make sense
+		 */
+		if (info.array.level != -4)
+			if (!(devices[j].state & (1<<MD_DISK_SYNC))) {
+				if (!(devices[j].state & (1<<MD_DISK_FAULTY)))
+					sparecnt++;
+				continue;
+			}
+		if (devices[j].events+event_margin >=
+		    devices[most_recent].events) {
+			devices[j].uptodate = 1;
+			if (i < info.array.raid_disks) {
+				okcnt++;
+				avail[i]=1;
+			} else
+				sparecnt++;
+		}
+	}
+	while (force && !enough(info.array.level, info.array.raid_disks,
+				info.array.layout, 1,
+				avail, okcnt)) {
+		/* Choose the newest best drive which is
+		 * not up-to-date, update the superblock
+		 * and add it.
+		 */
+		int fd;
+		long long current_events;
+		chosen_drive = -1;
+		for (i=0; i<info.array.raid_disks && i < bestcnt; i++) {
+			int j = best[i];
+			if (j>=0 &&
+			    !devices[j].uptodate &&
+			    devices[j].events > 0 &&
+			    (chosen_drive < 0 ||
+			     devices[j].events > devices[chosen_drive].events))
+				chosen_drive = j;
+		}
+		if (chosen_drive < 0)
+			break;
+		current_events = devices[chosen_drive].events;
+	add_another:
+		if (verbose >= 0)
+			fprintf(stderr, Name ": forcing event count in %s(%d) from %d upto %d\n",
+				devices[chosen_drive].devname, devices[chosen_drive].raid_disk,
+				(int)(devices[chosen_drive].events),
+				(int)(devices[most_recent].events));
+		fd = dev_open(devices[chosen_drive].devname, O_RDWR|O_EXCL);
+		if (fd < 0) {
+			fprintf(stderr, Name ": Couldn't open %s for write - not updating\n",
+				devices[chosen_drive].devname);
+			devices[chosen_drive].events = 0;
+			continue;
+		}
+		if (st->ss->load_super(st,fd, &super, NULL)) {
+			close(fd);
+			fprintf(stderr, Name ": RAID superblock disappeared from %s - not updating.\n",
+				devices[chosen_drive].devname);
+			devices[chosen_drive].events = 0;
+			continue;
+		}
+		info.events = devices[most_recent].events;
+		st->ss->update_super(&info, super, "force-one",
+				     devices[chosen_drive].devname, verbose,
+				     0, NULL);
+
+		if (st->ss->store_super(st, fd, super)) {
+			close(fd);
+			fprintf(stderr, Name ": Could not re-write superblock on %s\n",
+				devices[chosen_drive].devname);
+			devices[chosen_drive].events = 0;
+			free(super);
+			continue;
+		}
+		close(fd);
+		devices[chosen_drive].events = devices[most_recent].events;
+		devices[chosen_drive].uptodate = 1;
+		avail[chosen_drive] = 1;
+		okcnt++;
+		free(super);
+
+		/* If there are any other drives of the same vintage,
+		 * add them in as well.  We can't lose and we might gain
+		 */
+		for (i=0; i<info.array.raid_disks && i < bestcnt ; i++) {
+			int j = best[i];
+			if (j >= 0 &&
+			    !devices[j].uptodate &&
+			    devices[j].events > 0 &&
+			    devices[j].events == current_events) {
+				chosen_drive = j;
+				goto add_another;
+			}
+		}
+	}
+
+	/* Now we want to look at the superblock which the kernel will base things on
+	 * and compare the devices that we think are working with the devices that the
+	 * superblock thinks are working.
+	 * If there are differences and --force is given, then update this chosen
+	 * superblock.
+	 */
+	chosen_drive = -1;
+	super = NULL;
+	for (i=0; chosen_drive < 0 && i<bestcnt; i++) {
+		int j = best[i];
+		int fd;
+
+		if (j<0)
+			continue;
+		if (!devices[j].uptodate)
+			continue;
+		chosen_drive = j;
+		if ((fd=dev_open(devices[j].devname, O_RDONLY|O_EXCL))< 0) {
+			fprintf(stderr, Name ": Cannot open %s: %s\n",
+				devices[j].devname, strerror(errno));
+			return 1;
+		}
+		if (st->ss->load_super(st,fd, &super, NULL)) {
+			close(fd);
+			fprintf(stderr, Name ": RAID superblock has disappeared from %s\n",
+				devices[j].devname);
+			return 1;
+		}
+		close(fd);
+	}
+	if (super == NULL) {
+		fprintf(stderr, Name ": No suitable drives found for %s\n", mddev);
+		return 1;
+	}
+	st->ss->getinfo_super(&info, super);
+	for (i=0; i<bestcnt; i++) {
+		int j = best[i];
+		unsigned int desired_state;
+
+		if (i < info.array.raid_disks)
+			desired_state = (1<<MD_DISK_ACTIVE) | (1<<MD_DISK_SYNC);
+		else
+			desired_state = 0;
+
+		if (j<0)
+			continue;
+		if (!devices[j].uptodate)
+			continue;
+		info.disk.number = devices[j].disk_nr;
+		info.disk.raid_disk = i;
+		info.disk.state = desired_state;
+
+		if (devices[j].uptodate &&
+		    st->ss->update_super(&info, super, "assemble", NULL, verbose, 0, NULL)) {
+			if (force) {
+				if (verbose >= 0)
+					fprintf(stderr, Name ": "
+						"clearing FAULTY flag for device %d in %s for %s\n",
+						j, mddev, devices[j].devname);
+				change = 1;
+			} else {
+				if (verbose >= -1)
+					fprintf(stderr, Name ": "
+						"device %d in %s has wrong state in superblock, but %s seems ok\n",
+						i, mddev, devices[j].devname);
+			}
+		}
+#if 0
+		if (!devices[j].uptodate &&
+		    !(super.disks[i].state & (1 << MD_DISK_FAULTY))) {
+			fprintf(stderr, Name ": devices %d of %s is not marked FAULTY in superblock, but cannot be found\n",
+				i, mddev);
+		}
+#endif
+	}
+	if (force && !clean &&
+	    !enough(info.array.level, info.array.raid_disks,
+		    info.array.layout, clean,
+		    avail, okcnt)) {
+		change += st->ss->update_super(&info, super, "force-array",
+					devices[chosen_drive].devname, verbose,
+					       0, NULL);
+		clean = 1;
+	}
+
+	if (change) {
+		int fd;
+		fd = dev_open(devices[chosen_drive].devname, O_RDWR|O_EXCL);
+		if (fd < 0) {
+			fprintf(stderr, Name ": Could not open %s for write - cannot Assemble array.\n",
+				devices[chosen_drive].devname);
+			return 1;
+		}
+		if (st->ss->store_super(st, fd, super)) {
+			close(fd);
+			fprintf(stderr, Name ": Could not re-write superblock on %s\n",
+				devices[chosen_drive].devname);
+			return 1;
+		}
+		close(fd);
+	}
+
+	/* count number of in-sync devices according to the superblock.
+	 * We must have this number to start the array without -s or -R
+	 */
+	req_cnt = info.array.working_disks;
+
+	/* Almost ready to actually *do* something */
+	if (!old_linux) {
+		int rv;
+		if ((vers % 100) >= 1) { /* can use different versions */
+			mdu_array_info_t inf;
+			memset(&inf, 0, sizeof(inf));
+			inf.major_version = st->ss->major;
+			inf.minor_version = st->minor_version;
+			rv = ioctl(mdfd, SET_ARRAY_INFO, &inf);
+		} else
+			rv = ioctl(mdfd, SET_ARRAY_INFO, NULL);
+
+		if (rv) {
+			fprintf(stderr, Name ": SET_ARRAY_INFO failed for %s: %s\n",
+				mddev, strerror(errno));
+			return 1;
+		}
+		if (ident->bitmap_fd >= 0) {
+			if (ioctl(mdfd, SET_BITMAP_FILE, ident->bitmap_fd) != 0) {
+				fprintf(stderr, Name ": SET_BITMAP_FILE failed.\n");
+				return 1;
+			}
+		} else if (ident->bitmap_file) {
+			/* From config file */
+			int bmfd = open(ident->bitmap_file, O_RDWR);
+			if (bmfd < 0) {
+				fprintf(stderr, Name ": Could not open bitmap file %s\n",
+					ident->bitmap_file);
+				return 1;
+			}
+			if (ioctl(mdfd, SET_BITMAP_FILE, bmfd) != 0) {
+				fprintf(stderr, Name ": Failed to set bitmapfile for %s\n", mddev);
+				close(bmfd);
+				return 1;
+			}
+			close(bmfd);
+		}
+
+		/* First, add the raid disks, but add the chosen one last */
+		for (i=0; i<= bestcnt; i++) {
+			int j;
+			if (i < bestcnt) {
+				j = best[i];
+				if (j == chosen_drive)
+					continue;
+			} else
+				j = chosen_drive;
+
+			if (j >= 0 /* && devices[j].uptodate */) {
+				mdu_disk_info_t disk;
+				memset(&disk, 0, sizeof(disk));
+				disk.major = devices[j].major;
+				disk.minor = devices[j].minor;
+				if (ioctl(mdfd, ADD_NEW_DISK, &disk)!=0) {
+					fprintf(stderr, Name ": failed to add %s to %s: %s\n",
+						devices[j].devname,
+						mddev,
+						strerror(errno));
+					if (i < info.array.raid_disks || i == bestcnt)
+						okcnt--;
+					else
+						sparecnt--;
+				} else if (verbose > 0)
+					fprintf(stderr, Name ": added %s to %s as %d\n",
+						devices[j].devname, mddev, devices[j].raid_disk);
+			} else if (verbose > 0 && i < info.array.raid_disks)
+				fprintf(stderr, Name ": no uptodate device for slot %d of %s\n",
+					i, mddev);
+		}
+		
+		if (runstop == 1 ||
+		    (runstop <= 0 &&
+		     ( enough(info.array.level, info.array.raid_disks,
+			      info.array.layout, clean, avail, okcnt) &&
+		       (okcnt >= req_cnt || start_partial_ok)
+			     ))) {
+			if (ioctl(mdfd, RUN_ARRAY, NULL)==0) {
+				if (verbose >= 0) {
+					fprintf(stderr, Name ": %s has been started with %d drive%s",
+						mddev, okcnt, okcnt==1?"":"s");
+					if (okcnt < info.array.raid_disks)
+						fprintf(stderr, " (out of %d)", info.array.raid_disks);
+					if (sparecnt)
+						fprintf(stderr, " and %d spare%s", sparecnt, sparecnt==1?"":"s");
+					fprintf(stderr, ".\n");
+				}
+				return 0;
+			}
+			fprintf(stderr, Name ": failed to RUN_ARRAY %s: %s\n",
+				mddev, strerror(errno));
+
+			if (!enough(info.array.level, info.array.raid_disks,
+				    info.array.layout, 1, avail, okcnt))
+				fprintf(stderr, Name ": Not enough devices to "
+					"start the array.\n");
+			else if (!enough(info.array.level,
+					 info.array.raid_disks,
+					 info.array.layout, clean,
+					 avail, okcnt))
+				fprintf(stderr, Name ": Not enough devices to "
+					"start the array while not clean "
+					"- consider --force.\n");
+
+			return 1;
+		}
+		if (runstop == -1) {
+			fprintf(stderr, Name ": %s assembled from %d drive%s",
+				mddev, okcnt, okcnt==1?"":"s");
+			if (okcnt != info.array.raid_disks)
+				fprintf(stderr, " (out of %d)", info.array.raid_disks);
+			fprintf(stderr, ", but not started.\n");
+			return 0;
+		}
+		if (verbose >= -1) {
+			fprintf(stderr, Name ": %s assembled from %d drive%s", mddev, okcnt, okcnt==1?"":"s");
+			if (sparecnt)
+				fprintf(stderr, " and %d spare%s", sparecnt, sparecnt==1?"":"s");
+			if (!enough(info.array.level, info.array.raid_disks,
+				    info.array.layout, 1, avail, okcnt))
+				fprintf(stderr, " - not enough to start the array.\n");
+			else if (!enough(info.array.level,
+					 info.array.raid_disks,
+					 info.array.layout, clean,
+					 avail, okcnt))
+				fprintf(stderr, " - not enough to start the "
+					"array while not clean - consider "
+					"--force.\n");
+			else {
+				if (req_cnt == info.array.raid_disks)
+					fprintf(stderr, " - need all %d to start it", req_cnt);
+				else
+					fprintf(stderr, " - need %d of %d to start", req_cnt, info.array.raid_disks);
+				fprintf(stderr, " (use --run to insist).\n");
+			}
+		}
+		return 1;
+	} else {
+		/* The "chosen_drive" is a good choice, and if necessary, the superblock has
+		 * been updated to point to the current locations of devices.
+		 * so we can just start the array
+		 */
+		unsigned long dev;
+		dev = makedev(devices[chosen_drive].major,
+			    devices[chosen_drive].minor);
+		if (ioctl(mdfd, START_ARRAY, dev)) {
+		    fprintf(stderr, Name ": Cannot start array: %s\n",
+			    strerror(errno));
+		}
+		
+	}
+	return 0;
+}
+
+int mdfd = -1;
+int runstop = 0;
+int readonly = 0;
+int verbose = 0;
+int force = 0;
+
+int mdassemble_main(int argc, char **argv) {
+	mddev_ident_t array_list =  conf_get_ident(NULL);
+	int minor;
+	if (!array_list) {
+		fprintf(stderr, Name ": No arrays found in config file\n");
+		return 1;
+	} else {
+		for (; array_list; array_list = array_list->next) {
+			mdu_array_info_t array;
+			if (!strncmp("/dev/md", array_list->devname, 7)) {
+			   	errno = 0;
+				minor = strtoul(array_list->devname + 7, NULL, 0);
+				if (!errno) {
+					mknod(array_list->devname, S_IFBLK|0600, makedev(MD_MAJOR, minor));
+				}
+			}
+			mdfd = open_mddev(array_list->devname, array_list->autof);
+			if (mdfd < 0) {
+
+				fprintf(stderr, Name ": failed to open array\n");
+				continue;
+			}
+			if (ioctl(mdfd, GET_ARRAY_INFO, &array) < 0) {
+				Assemble(array_list->st, array_list->devname, mdfd,
+					   array_list, NULL, NULL,
+					   readonly, runstop, NULL, NULL, verbose, force);
+			}
+			close(mdfd);
+		}
+	}
+	return 0;
+}
+
diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/mdadm/mdexamine.c busybox-1.7.4+gentoo+mdadm/mdadm/mdexamine.c
--- busybox-1.7.4+gentoo/mdadm/mdexamine.c	1969-12-31 16:00:00.000000000 -0800
+++ busybox-1.7.4+gentoo+mdadm/mdadm/mdexamine.c	2008-03-11 10:31:00.000000000 -0700
@@ -0,0 +1,157 @@
+/*
+ * mdadm - manage Linux "md" devices aka RAID arrays.
+ *
+ * Copyright (C) 2001-2006 Neil Brown <neilb@suse.de>
+ *
+ *
+ *    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
+ *
+ *    Author: Neil Brown
+ *    Email: <neilb@cse.unsw.edu.au>
+ *    Paper: Neil Brown
+ *           School of Computer Science and Engineering
+ *           The University of New South Wales
+ *           Sydney, 2052
+ *           Australia
+ */
+
+#include	"mdadm.h"
+#include	"dlink.h"
+
+#if ! defined(__BIG_ENDIAN) && ! defined(__LITTLE_ENDIAN)
+#error no endian defined
+#endif
+#include	"md_u.h"
+#include	"md_p.h"
+
+static int Examine(mddev_dev_t devlist, int brief, int scan,
+	    int SparcAdjust, struct supertype *forcest,
+	    char *homehost)
+{
+
+	/* Read the raid superblock from a device and
+	 * display important content.
+	 *
+	 * If cannot be found, print reason: too small, bad magic
+	 *
+	 * Print:
+	 *   version, ctime, level, size, raid+spare+
+	 *   prefered minor
+	 *   uuid
+	 *
+	 *   utime, state etc
+	 *
+	 * If (brief) gather devices for same array and just print a mdadm.conf line including devices=
+	 * if devlist==NULL, use conf_get_devs()
+	 */
+	int fd; 
+	void *super = NULL;
+	int rv = 0;
+	int err = 0;
+
+	struct array {
+		void *super;
+		struct supertype *st;
+		struct mdinfo info;
+		void *devs;
+		struct array *next;
+		int spares;
+	} *arrays = NULL;
+
+	for (; devlist ; devlist=devlist->next) {
+		struct supertype *st = forcest;
+
+		fd = dev_open(devlist->devname, O_RDONLY);
+		if (fd < 0) {
+			if (!scan) {
+				fprintf(stderr,Name ": cannot open %s: %s\n",
+					devlist->devname, strerror(errno));
+				rv = 1;
+			}
+			err = 1;
+		}
+		else {
+			if (!st)
+				st = guess_super(fd);
+			if (st)
+				err = st->ss->load_super(st, fd, &super, (brief||scan)?NULL:devlist->devname);
+			else {
+				if (!brief) {
+					fprintf(stderr, Name ": No md superblock detected on %s.\n", devlist->devname);
+					rv = 1;
+				}
+				err = 1;
+			}
+			close(fd);
+		}
+		if (err)
+			continue;
+
+		if (SparcAdjust)
+			st->ss->update_super(NULL, super, "sparc2.2", devlist->devname, 0, 0, NULL);
+		/* Ok, its good enough to try, though the checksum could be wrong */
+		if (brief) {
+			struct array *ap;
+			char *d;
+			for (ap=arrays; ap; ap=ap->next) {
+				if (st->ss == ap->st->ss && st->ss->compare_super(&ap->super, super)==0)
+					break;
+			}
+			if (!ap) {
+				ap = malloc(sizeof(*ap));
+				ap->super = super;
+				ap->devs = dl_head();
+				ap->next = arrays;
+				ap->spares = 0;
+				ap->st = st;
+				arrays = ap;
+				st->ss->getinfo_super(&ap->info, super);
+			} else {
+				st->ss->getinfo_super(&ap->info, super);
+				free(super);
+			}
+			if (!(ap->info.disk.state & MD_DISK_SYNC))
+				ap->spares++;
+			d = dl_strdup(devlist->devname);
+			dl_add(ap->devs, d);
+		}
+	}
+	if (brief) {
+		struct array *ap;
+		for (ap=arrays; ap; ap=ap->next) {
+			char sep='=';
+			char *d;
+			ap->st->ss->brief_examine_super(ap->super);
+			if (ap->spares) printf("   spares=%d", ap->spares);
+			if (brief > 1) {
+				printf("   devices");
+				for (d=dl_next(ap->devs); d!= ap->devs; d=dl_next(d)) {
+					printf("%c%s", sep, d);
+					sep=',';
+				}
+			}
+			free(ap->super);
+			/* FIXME free ap */
+			if (ap->spares || brief > 1)
+				printf("\n");
+		}
+	}
+	return rv;
+}
+
+int mdexamine_main(int argc, char **argv) {
+	return Examine(conf_get_devs(), 1, 0, 0, NULL, NULL);
+}
+
diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/mdadm/md_p.h busybox-1.7.4+gentoo+mdadm/mdadm/md_p.h
--- busybox-1.7.4+gentoo/mdadm/md_p.h	1969-12-31 16:00:00.000000000 -0800
+++ busybox-1.7.4+gentoo+mdadm/mdadm/md_p.h	2008-03-11 10:31:00.000000000 -0700
@@ -0,0 +1,194 @@
+/*
+   md_p.h : physical layout of Linux RAID devices
+          Copyright (C) 1996-98 Ingo Molnar, Gadi Oxman
+	  
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+   
+   You should have received a copy of the GNU General Public License
+   (for example /usr/src/linux/COPYING); if not, write to the Free
+   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
+*/
+
+#ifndef _MD_P_H
+#define _MD_P_H
+
+/*
+ * RAID superblock.
+ *
+ * The RAID superblock maintains some statistics on each RAID configuration.
+ * Each real device in the RAID set contains it near the end of the device.
+ * Some of the ideas are copied from the ext2fs implementation.
+ *
+ * We currently use 4096 bytes as follows:
+ *
+ *	word offset	function
+ *
+ *	   0  -    31	Constant generic RAID device information.
+ *        32  -    63   Generic state information.
+ *	  64  -   127	Personality specific information.
+ *	 128  -   511	12 32-words descriptors of the disks in the raid set.
+ *	 512  -   911	Reserved.
+ *	 912  -  1023	Disk specific descriptor.
+ */
+
+/*
+ * If x is the real device size in bytes, we return an apparent size of:
+ *
+ *	y = (x & ~(MD_RESERVED_BYTES - 1)) - MD_RESERVED_BYTES
+ *
+ * and place the 4kB superblock at offset y.
+ */
+#define MD_RESERVED_BYTES		(64 * 1024)
+#define MD_RESERVED_SECTORS		(MD_RESERVED_BYTES / 512)
+#define MD_RESERVED_BLOCKS		(MD_RESERVED_BYTES / BLOCK_SIZE)
+
+#define MD_NEW_SIZE_SECTORS(x)		((x & ~(MD_RESERVED_SECTORS - 1)) - MD_RESERVED_SECTORS)
+#define MD_NEW_SIZE_BLOCKS(x)		((x & ~(MD_RESERVED_BLOCKS - 1)) - MD_RESERVED_BLOCKS)
+
+#define MD_SB_BYTES			4096
+#define MD_SB_WORDS			(MD_SB_BYTES / 4)
+#define MD_SB_BLOCKS			(MD_SB_BYTES / BLOCK_SIZE)
+#define MD_SB_SECTORS			(MD_SB_BYTES / 512)
+
+/*
+ * The following are counted in 32-bit words
+ */
+#define	MD_SB_GENERIC_OFFSET		0
+#define MD_SB_PERSONALITY_OFFSET	64
+#define MD_SB_DISKS_OFFSET		128
+#define MD_SB_DESCRIPTOR_OFFSET		992
+
+#define MD_SB_GENERIC_CONSTANT_WORDS	32
+#define MD_SB_GENERIC_STATE_WORDS	32
+#define MD_SB_GENERIC_WORDS		(MD_SB_GENERIC_CONSTANT_WORDS + MD_SB_GENERIC_STATE_WORDS)
+#define MD_SB_PERSONALITY_WORDS		64
+#define MD_SB_DESCRIPTOR_WORDS		32
+#define MD_SB_DISKS			27
+#define MD_SB_DISKS_WORDS		(MD_SB_DISKS*MD_SB_DESCRIPTOR_WORDS)
+#define MD_SB_RESERVED_WORDS		(1024 - MD_SB_GENERIC_WORDS - MD_SB_PERSONALITY_WORDS - MD_SB_DISKS_WORDS - MD_SB_DESCRIPTOR_WORDS)
+#define MD_SB_EQUAL_WORDS		(MD_SB_GENERIC_WORDS + MD_SB_PERSONALITY_WORDS + MD_SB_DISKS_WORDS)
+
+/*
+ * Device "operational" state bits
+ */
+#define MD_DISK_FAULTY		0 /* disk is faulty / operational */
+#define MD_DISK_ACTIVE		1 /* disk is running or spare disk */
+#define MD_DISK_SYNC		2 /* disk is in sync with the raid set */
+#define MD_DISK_REMOVED		3 /* disk is in sync with the raid set */
+
+#define	MD_DISK_WRITEMOSTLY	9 /* disk is "write-mostly" is RAID1 config.
+				   * read requests will only be sent here in 
+				   * dire need
+				   */
+
+typedef struct mdp_device_descriptor_s {
+	__u32 number;		/* 0 Device number in the entire set	      */
+	__u32 major;		/* 1 Device major number		      */
+	__u32 minor;		/* 2 Device minor number		      */
+	__u32 raid_disk;	/* 3 The role of the device in the raid set   */
+	__u32 state;		/* 4 Operational state			      */
+	__u32 reserved[MD_SB_DESCRIPTOR_WORDS - 5];
+} mdp_disk_t;
+
+#define MD_SB_MAGIC		0xa92b4efc
+
+/*
+ * Superblock state bits
+ */
+#define MD_SB_CLEAN		0
+#define MD_SB_ERRORS		1
+
+#define	MD_SB_BITMAP_PRESENT	8 /* bitmap may be present nearby */
+
+typedef struct mdp_superblock_s {
+	/*
+	 * Constant generic information
+	 */
+	__u32 md_magic;		/*  0 MD identifier 			      */
+	__u32 major_version;	/*  1 major version to which the set conforms */
+	__u32 minor_version;	/*  2 minor version ...			      */
+	__u32 patch_version;	/*  3 patchlevel version ...		      */
+	__u32 gvalid_words;	/*  4 Number of used words in this section    */
+	__u32 set_uuid0;	/*  5 Raid set identifier		      */
+	__u32 ctime;		/*  6 Creation time			      */
+	__u32 level;		/*  7 Raid personality			      */
+	__u32 size;		/*  8 Apparent size of each individual disk   */
+	__u32 nr_disks;		/*  9 total disks in the raid set	      */
+	__u32 raid_disks;	/* 10 disks in a fully functional raid set    */
+	__u32 md_minor;		/* 11 preferred MD minor device number	      */
+	__u32 not_persistent;	/* 12 does it have a persistent superblock    */
+	__u32 set_uuid1;	/* 13 Raid set identifier #2		      */
+	__u32 set_uuid2;	/* 14 Raid set identifier #3		      */
+	__u32 set_uuid3;	/* 15 Raid set identifier #4		      */
+	__u32 gstate_creserved[MD_SB_GENERIC_CONSTANT_WORDS - 16];
+
+	/*
+	 * Generic state information
+	 */
+	__u32 utime;		/*  0 Superblock update time		      */
+	__u32 state;		/*  1 State bits (clean, ...)		      */
+	__u32 active_disks;	/*  2 Number of currently active disks	      */
+	__u32 working_disks;	/*  3 Number of working disks		      */
+	__u32 failed_disks;	/*  4 Number of failed disks		      */
+	__u32 spare_disks;	/*  5 Number of spare disks		      */
+	__u32 sb_csum;		/*  6 checksum of the whole superblock        */
+#if  __BYTE_ORDER ==  __BIG_ENDIAN
+	__u32 events_hi;	/*  7 high-order of superblock update count   */
+	__u32 events_lo;	/*  8 low-order of superblock update count    */
+	__u32 cp_events_hi;	/*  9 high-order of checkpoint update count   */
+	__u32 cp_events_lo;	/* 10 low-order of checkpoint update count    */
+#else
+	__u32 events_lo;	/*  7 low-order of superblock update count    */
+	__u32 events_hi;	/*  8 high-order of superblock update count   */
+	__u32 cp_events_lo;	/*  9 low-order of checkpoint update count    */
+	__u32 cp_events_hi;	/* 10 high-order of checkpoint update count   */
+#endif
+	__u32 recovery_cp;	/* 11 recovery checkpoint sector count	      */
+	/* There are only valid for minor_version > 90 */
+	__u64 reshape_position;	/* 12,13 next address in array-space for reshape */
+	__u32 new_level;	/* 14 new level we are reshaping to	      */
+	__u32 delta_disks;	/* 15 change in number of raid_disks	      */
+	__u32 new_layout;	/* 16 new layout			      */
+	__u32 new_chunk;	/* 17 new chunk size (bytes)		      */
+	__u32 gstate_sreserved[MD_SB_GENERIC_STATE_WORDS - 18];
+
+	/*
+	 * Personality information
+	 */
+	__u32 layout;		/*  0 the array's physical layout	      */
+	__u32 chunk_size;	/*  1 chunk size in bytes		      */
+	__u32 root_pv;		/*  2 LV root PV */
+	__u32 root_block;	/*  3 LV root block */
+	__u32 pstate_reserved[MD_SB_PERSONALITY_WORDS - 4];
+
+	/*
+	 * Disks information
+	 */
+	mdp_disk_t disks[MD_SB_DISKS];
+
+	/*
+	 * Reserved
+	 */
+	__u32 reserved[MD_SB_RESERVED_WORDS];
+
+	/*
+	 * Active descriptor
+	 */
+	mdp_disk_t this_disk;
+
+} mdp_super_t;
+
+#ifdef __TINYC__
+typedef unsigned long long __u64;
+#endif
+
+static inline __u64 md_event(mdp_super_t *sb) {
+	__u64 ev = sb->events_hi;
+	return (ev<<32)| sb->events_lo;
+}
+
+#endif 
+
diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/mdadm/md_u.h busybox-1.7.4+gentoo+mdadm/mdadm/md_u.h
--- busybox-1.7.4+gentoo/mdadm/md_u.h	1969-12-31 16:00:00.000000000 -0800
+++ busybox-1.7.4+gentoo+mdadm/mdadm/md_u.h	2008-03-11 10:31:00.000000000 -0700
@@ -0,0 +1,123 @@
+/*
+   md_u.h : user <=> kernel API between Linux raidtools and RAID drivers
+          Copyright (C) 1998 Ingo Molnar
+	  
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+   
+   You should have received a copy of the GNU General Public License
+   (for example /usr/src/linux/COPYING); if not, write to the Free
+   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
+*/
+
+#ifndef _MD_U_H
+#define _MD_U_H
+
+/* ioctls */
+
+/* status */
+#define RAID_VERSION		_IOR (MD_MAJOR, 0x10, mdu_version_t)
+#define GET_ARRAY_INFO		_IOR (MD_MAJOR, 0x11, mdu_array_info_t)
+#define GET_DISK_INFO		_IOR (MD_MAJOR, 0x12, mdu_disk_info_t)
+#define PRINT_RAID_DEBUG	_IO (MD_MAJOR, 0x13)
+#define RAID_AUTORUN		_IO (MD_MAJOR, 0x14)
+#define GET_BITMAP_FILE		_IOR (MD_MAJOR, 0x15, mdu_bitmap_file_t)
+
+/* configuration */
+#define CLEAR_ARRAY		_IO (MD_MAJOR, 0x20)
+#define ADD_NEW_DISK		_IOW (MD_MAJOR, 0x21, mdu_disk_info_t)
+#define HOT_REMOVE_DISK		_IO (MD_MAJOR, 0x22)
+#define SET_ARRAY_INFO		_IOW (MD_MAJOR, 0x23, mdu_array_info_t)
+#define SET_DISK_INFO		_IO (MD_MAJOR, 0x24)
+#define WRITE_RAID_INFO		_IO (MD_MAJOR, 0x25)
+#define UNPROTECT_ARRAY		_IO (MD_MAJOR, 0x26)
+#define PROTECT_ARRAY		_IO (MD_MAJOR, 0x27)
+#define HOT_ADD_DISK		_IO (MD_MAJOR, 0x28)
+#define SET_DISK_FAULTY		_IO (MD_MAJOR, 0x29)
+#define SET_BITMAP_FILE		_IOW (MD_MAJOR, 0x2b, int)
+
+/* usage */
+#define RUN_ARRAY		_IOW (MD_MAJOR, 0x30, mdu_param_t)
+#define START_ARRAY		_IO (MD_MAJOR, 0x31)
+#define STOP_ARRAY		_IO (MD_MAJOR, 0x32)
+#define STOP_ARRAY_RO		_IO (MD_MAJOR, 0x33)
+#define RESTART_ARRAY_RW	_IO (MD_MAJOR, 0x34)
+
+typedef struct mdu_version_s {
+	int major;
+	int minor;
+	int patchlevel;
+} mdu_version_t;
+
+typedef struct mdu_array_info_s {
+	/*
+	 * Generic constant information
+	 */
+	int major_version;
+	int minor_version;
+	int patch_version;
+	int ctime;
+	int level;
+	int size;
+	int nr_disks;
+	int raid_disks;
+	int md_minor;
+	int not_persistent;
+
+	/*
+	 * Generic state information
+	 */
+	int utime;		/*  0 Superblock update time		      */
+	int state;		/*  1 State bits (clean, ...)		      */
+	int active_disks;	/*  2 Number of currently active disks	      */
+	int working_disks;	/*  3 Number of working disks		      */
+	int failed_disks;	/*  4 Number of failed disks		      */
+	int spare_disks;	/*  5 Number of spare disks		      */
+
+	/*
+	 * Personality information
+	 */
+	int layout;		/*  0 the array's physical layout	      */
+	int chunk_size;	/*  1 chunk size in bytes		      */
+
+} mdu_array_info_t;
+
+typedef struct mdu_disk_info_s {
+	/*
+	 * configuration/status of one particular disk
+	 */
+	int number;
+	int major;
+	int minor;
+	int raid_disk;
+	int state;
+
+} mdu_disk_info_t;
+
+typedef struct mdu_start_info_s {
+	/*
+	 * configuration/status of one particular disk
+	 */
+	int major;
+	int minor;
+	int raid_disk;
+	int state;
+
+} mdu_start_info_t;
+
+typedef struct mdu_bitmap_file_s
+{
+	char pathname[4096];
+} mdu_bitmap_file_t;
+
+typedef struct mdu_param_s
+{
+	int			personality;	/* 1,2,3,4 */
+	int			chunk_size;	/* in bytes */
+	int			max_fault;	/* unused for now */
+} mdu_param_t;
+
+#endif 
+
diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/mdadm/sha1.c busybox-1.7.4+gentoo+mdadm/mdadm/sha1.c
--- busybox-1.7.4+gentoo/mdadm/sha1.c	1969-12-31 16:00:00.000000000 -0800
+++ busybox-1.7.4+gentoo+mdadm/mdadm/sha1.c	2008-03-11 10:31:00.000000000 -0700
@@ -0,0 +1,423 @@
+/* sha1.c - Functions to compute SHA1 message digest of files or
+   memory blocks according to the NIST specification FIPS-180-1.
+
+   Copyright (C) 2000, 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any
+   later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+/* Written by Scott G. Miller
+   Credits:
+      Robert Klep <robert@ilse.nl>  -- Expansion function fix
+*/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "sha1.h"
+
+#include <stddef.h>
+#include <string.h>
+
+#if USE_UNLOCKED_IO
+# include "unlocked-io.h"
+#endif
+
+/* SWAP does an endian swap on architectures that are little-endian,
+   as SHA1 needs some data in a big-endian form.  */
+
+#ifdef WORDS_BIGENDIAN
+# define SWAP(n) (n)
+#else
+# define SWAP(n) \
+    (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))
+#endif
+
+#define BLOCKSIZE 4096
+#if BLOCKSIZE % 64 != 0
+# error "invalid BLOCKSIZE"
+#endif
+
+/* This array contains the bytes used to pad the buffer to the next
+   64-byte boundary.  (RFC 1321, 3.1: Step 1)  */
+static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ...  */ };
+
+
+/*
+  Takes a pointer to a 160 bit block of data (five 32 bit ints) and
+  intializes it to the start constants of the SHA1 algorithm.  This
+  must be called before using hash in the call to sha1_hash.
+*/
+void
+sha1_init_ctx (struct sha1_ctx *ctx)
+{
+  ctx->A = 0x67452301;
+  ctx->B = 0xefcdab89;
+  ctx->C = 0x98badcfe;
+  ctx->D = 0x10325476;
+  ctx->E = 0xc3d2e1f0;
+
+  ctx->total[0] = ctx->total[1] = 0;
+  ctx->buflen = 0;
+}
+
+/* Put result from CTX in first 20 bytes following RESBUF.  The result
+   must be in little endian byte order.
+
+   IMPORTANT: On some systems it is required that RESBUF is correctly
+   aligned for a 32 bits value.  */
+void *
+sha1_read_ctx (const struct sha1_ctx *ctx, void *resbuf)
+{
+  ((md5_uint32 *) resbuf)[0] = SWAP (ctx->A);
+  ((md5_uint32 *) resbuf)[1] = SWAP (ctx->B);
+  ((md5_uint32 *) resbuf)[2] = SWAP (ctx->C);
+  ((md5_uint32 *) resbuf)[3] = SWAP (ctx->D);
+  ((md5_uint32 *) resbuf)[4] = SWAP (ctx->E);
+
+  return resbuf;
+}
+
+/* Process the remaining bytes in the internal buffer and the usual
+   prolog according to the standard and write the result to RESBUF.
+
+   IMPORTANT: On some systems it is required that RESBUF is correctly
+   aligned for a 32 bits value.  */
+void *
+sha1_finish_ctx (struct sha1_ctx *ctx, void *resbuf)
+{
+  /* Take yet unprocessed bytes into account.  */
+  md5_uint32 bytes = ctx->buflen;
+  size_t pad;
+
+  /* Now count remaining bytes.  */
+  ctx->total[0] += bytes;
+  if (ctx->total[0] < bytes)
+    ++ctx->total[1];
+
+  pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
+  memcpy (&ctx->buffer[bytes], fillbuf, pad);
+
+  /* Put the 64-bit file length in *bits* at the end of the buffer.  */
+  *(md5_uint32 *) &ctx->buffer[bytes + pad + 4] = SWAP (ctx->total[0] << 3);
+  *(md5_uint32 *) &ctx->buffer[bytes + pad] = SWAP ((ctx->total[1] << 3) |
+						    (ctx->total[0] >> 29));
+
+  /* Process last bytes.  */
+  sha1_process_block (ctx->buffer, bytes + pad + 8, ctx);
+
+  return sha1_read_ctx (ctx, resbuf);
+}
+
+/* Compute SHA1 message digest for bytes read from STREAM.  The
+   resulting message digest number will be written into the 16 bytes
+   beginning at RESBLOCK.  */
+int
+sha1_stream (FILE *stream, void *resblock)
+{
+  struct sha1_ctx ctx;
+  char buffer[BLOCKSIZE + 72];
+  size_t sum;
+
+  /* Initialize the computation context.  */
+  sha1_init_ctx (&ctx);
+
+  /* Iterate over full file contents.  */
+  while (1)
+    {
+      /* We read the file in blocks of BLOCKSIZE bytes.  One call of the
+	 computation function processes the whole buffer so that with the
+	 next round of the loop another block can be read.  */
+      size_t n;
+      sum = 0;
+
+      /* Read block.  Take care for partial reads.  */
+      while (1)
+	{
+	  n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream);
+
+	  sum += n;
+
+	  if (sum == BLOCKSIZE)
+	    break;
+
+	  if (n == 0)
+	    {
+	      /* Check for the error flag IFF N == 0, so that we don't
+		 exit the loop after a partial read due to e.g., EAGAIN
+		 or EWOULDBLOCK.  */
+	      if (ferror (stream))
+		return 1;
+	      goto process_partial_block;
+	    }
+
+	  /* We've read at least one byte, so ignore errors.  But always
+	     check for EOF, since feof may be true even though N > 0.
+	     Otherwise, we could end up calling fread after EOF.  */
+	  if (feof (stream))
+	    goto process_partial_block;
+	}
+
+      /* Process buffer with BLOCKSIZE bytes.  Note that
+			BLOCKSIZE % 64 == 0
+       */
+      sha1_process_block (buffer, BLOCKSIZE, &ctx);
+    }
+
+ process_partial_block:;
+
+  /* Process any remaining bytes.  */
+  if (sum > 0)
+    sha1_process_bytes (buffer, sum, &ctx);
+
+  /* Construct result in desired memory.  */
+  sha1_finish_ctx (&ctx, resblock);
+  return 0;
+}
+
+/* Compute MD5 message digest for LEN bytes beginning at BUFFER.  The
+   result is always in little endian byte order, so that a byte-wise
+   output yields to the wanted ASCII representation of the message
+   digest.  */
+void *
+sha1_buffer (const char *buffer, size_t len, void *resblock)
+{
+  struct sha1_ctx ctx;
+
+  /* Initialize the computation context.  */
+  sha1_init_ctx (&ctx);
+
+  /* Process whole buffer but last len % 64 bytes.  */
+  sha1_process_bytes (buffer, len, &ctx);
+
+  /* Put result in desired memory area.  */
+  return sha1_finish_ctx (&ctx, resblock);
+}
+
+void
+sha1_process_bytes (const void *buffer, size_t len, struct sha1_ctx *ctx)
+{
+  /* When we already have some bits in our internal buffer concatenate
+     both inputs first.  */
+  if (ctx->buflen != 0)
+    {
+      size_t left_over = ctx->buflen;
+      size_t add = 128 - left_over > len ? len : 128 - left_over;
+
+      memcpy (&ctx->buffer[left_over], buffer, add);
+      ctx->buflen += add;
+
+      if (ctx->buflen > 64)
+	{
+	  sha1_process_block (ctx->buffer, ctx->buflen & ~63, ctx);
+
+	  ctx->buflen &= 63;
+	  /* The regions in the following copy operation cannot overlap.  */
+	  memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63],
+		  ctx->buflen);
+	}
+
+      buffer = (const char *) buffer + add;
+      len -= add;
+    }
+
+  /* Process available complete blocks.  */
+  if (len >= 64)
+    {
+#if !_STRING_ARCH_unaligned
+# define alignof(type) offsetof (struct { char c; type x; }, x)
+# define UNALIGNED_P(p) (((size_t) p) % alignof (md5_uint32) != 0)
+      if (UNALIGNED_P (buffer))
+	while (len > 64)
+	  {
+	    sha1_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx);
+	    buffer = (const char *) buffer + 64;
+	    len -= 64;
+	  }
+      else
+#endif
+	{
+	  sha1_process_block (buffer, len & ~63, ctx);
+	  buffer = (const char *) buffer + (len & ~63);
+	  len &= 63;
+	}
+    }
+
+  /* Move remaining bytes in internal buffer.  */
+  if (len > 0)
+    {
+      size_t left_over = ctx->buflen;
+
+      memcpy (&ctx->buffer[left_over], buffer, len);
+      left_over += len;
+      if (left_over >= 64)
+	{
+	  sha1_process_block (ctx->buffer, 64, ctx);
+	  left_over -= 64;
+	  memcpy (ctx->buffer, &ctx->buffer[64], left_over);
+	}
+      ctx->buflen = left_over;
+    }
+}
+
+/* --- Code below is the primary difference between md5.c and sha1.c --- */
+
+/* SHA1 round constants */
+#define K1 0x5a827999L
+#define K2 0x6ed9eba1L
+#define K3 0x8f1bbcdcL
+#define K4 0xca62c1d6L
+
+/* Round functions.  Note that F2 is the same as F4.  */
+#define F1(B,C,D) ( D ^ ( B & ( C ^ D ) ) )
+#define F2(B,C,D) (B ^ C ^ D)
+#define F3(B,C,D) ( ( B & C ) | ( D & ( B | C ) ) )
+#define F4(B,C,D) (B ^ C ^ D)
+
+/* Process LEN bytes of BUFFER, accumulating context into CTX.
+   It is assumed that LEN % 64 == 0.
+   Most of this code comes from GnuPG's cipher/sha1.c.  */
+
+void
+sha1_process_block (const void *buffer, size_t len, struct sha1_ctx *ctx)
+{
+  const md5_uint32 *words = buffer;
+  size_t nwords = len / sizeof (md5_uint32);
+  const md5_uint32 *endp = words + nwords;
+  md5_uint32 x[16];
+  md5_uint32 a = ctx->A;
+  md5_uint32 b = ctx->B;
+  md5_uint32 c = ctx->C;
+  md5_uint32 d = ctx->D;
+  md5_uint32 e = ctx->E;
+
+  /* First increment the byte count.  RFC 1321 specifies the possible
+     length of the file up to 2^64 bits.  Here we only compute the
+     number of bytes.  Do a double word increment.  */
+  ctx->total[0] += len;
+  if (ctx->total[0] < len)
+    ++ctx->total[1];
+
+#define rol(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+#define M(I) ( tm =   x[I&0x0f] ^ x[(I-14)&0x0f] \
+		    ^ x[(I-8)&0x0f] ^ x[(I-3)&0x0f] \
+	       , (x[I&0x0f] = rol(tm, 1)) )
+
+#define R(A,B,C,D,E,F,K,M)  do { E += rol( A, 5 )     \
+				      + F( B, C, D )  \
+				      + K	      \
+				      + M;	      \
+				 B = rol( B, 30 );    \
+			       } while(0)
+
+  while (words < endp)
+    {
+      md5_uint32 tm;
+      int t;
+      for (t = 0; t < 16; t++)
+	{
+	  x[t] = SWAP (*words);
+	  words++;
+	}
+
+      R( a, b, c, d, e, F1, K1, x[ 0] );
+      R( e, a, b, c, d, F1, K1, x[ 1] );
+      R( d, e, a, b, c, F1, K1, x[ 2] );
+      R( c, d, e, a, b, F1, K1, x[ 3] );
+      R( b, c, d, e, a, F1, K1, x[ 4] );
+      R( a, b, c, d, e, F1, K1, x[ 5] );
+      R( e, a, b, c, d, F1, K1, x[ 6] );
+      R( d, e, a, b, c, F1, K1, x[ 7] );
+      R( c, d, e, a, b, F1, K1, x[ 8] );
+      R( b, c, d, e, a, F1, K1, x[ 9] );
+      R( a, b, c, d, e, F1, K1, x[10] );
+      R( e, a, b, c, d, F1, K1, x[11] );
+      R( d, e, a, b, c, F1, K1, x[12] );
+      R( c, d, e, a, b, F1, K1, x[13] );
+      R( b, c, d, e, a, F1, K1, x[14] );
+      R( a, b, c, d, e, F1, K1, x[15] );
+      R( e, a, b, c, d, F1, K1, M(16) );
+      R( d, e, a, b, c, F1, K1, M(17) );
+      R( c, d, e, a, b, F1, K1, M(18) );
+      R( b, c, d, e, a, F1, K1, M(19) );
+      R( a, b, c, d, e, F2, K2, M(20) );
+      R( e, a, b, c, d, F2, K2, M(21) );
+      R( d, e, a, b, c, F2, K2, M(22) );
+      R( c, d, e, a, b, F2, K2, M(23) );
+      R( b, c, d, e, a, F2, K2, M(24) );
+      R( a, b, c, d, e, F2, K2, M(25) );
+      R( e, a, b, c, d, F2, K2, M(26) );
+      R( d, e, a, b, c, F2, K2, M(27) );
+      R( c, d, e, a, b, F2, K2, M(28) );
+      R( b, c, d, e, a, F2, K2, M(29) );
+      R( a, b, c, d, e, F2, K2, M(30) );
+      R( e, a, b, c, d, F2, K2, M(31) );
+      R( d, e, a, b, c, F2, K2, M(32) );
+      R( c, d, e, a, b, F2, K2, M(33) );
+      R( b, c, d, e, a, F2, K2, M(34) );
+      R( a, b, c, d, e, F2, K2, M(35) );
+      R( e, a, b, c, d, F2, K2, M(36) );
+      R( d, e, a, b, c, F2, K2, M(37) );
+      R( c, d, e, a, b, F2, K2, M(38) );
+      R( b, c, d, e, a, F2, K2, M(39) );
+      R( a, b, c, d, e, F3, K3, M(40) );
+      R( e, a, b, c, d, F3, K3, M(41) );
+      R( d, e, a, b, c, F3, K3, M(42) );
+      R( c, d, e, a, b, F3, K3, M(43) );
+      R( b, c, d, e, a, F3, K3, M(44) );
+      R( a, b, c, d, e, F3, K3, M(45) );
+      R( e, a, b, c, d, F3, K3, M(46) );
+      R( d, e, a, b, c, F3, K3, M(47) );
+      R( c, d, e, a, b, F3, K3, M(48) );
+      R( b, c, d, e, a, F3, K3, M(49) );
+      R( a, b, c, d, e, F3, K3, M(50) );
+      R( e, a, b, c, d, F3, K3, M(51) );
+      R( d, e, a, b, c, F3, K3, M(52) );
+      R( c, d, e, a, b, F3, K3, M(53) );
+      R( b, c, d, e, a, F3, K3, M(54) );
+      R( a, b, c, d, e, F3, K3, M(55) );
+      R( e, a, b, c, d, F3, K3, M(56) );
+      R( d, e, a, b, c, F3, K3, M(57) );
+      R( c, d, e, a, b, F3, K3, M(58) );
+      R( b, c, d, e, a, F3, K3, M(59) );
+      R( a, b, c, d, e, F4, K4, M(60) );
+      R( e, a, b, c, d, F4, K4, M(61) );
+      R( d, e, a, b, c, F4, K4, M(62) );
+      R( c, d, e, a, b, F4, K4, M(63) );
+      R( b, c, d, e, a, F4, K4, M(64) );
+      R( a, b, c, d, e, F4, K4, M(65) );
+      R( e, a, b, c, d, F4, K4, M(66) );
+      R( d, e, a, b, c, F4, K4, M(67) );
+      R( c, d, e, a, b, F4, K4, M(68) );
+      R( b, c, d, e, a, F4, K4, M(69) );
+      R( a, b, c, d, e, F4, K4, M(70) );
+      R( e, a, b, c, d, F4, K4, M(71) );
+      R( d, e, a, b, c, F4, K4, M(72) );
+      R( c, d, e, a, b, F4, K4, M(73) );
+      R( b, c, d, e, a, F4, K4, M(74) );
+      R( a, b, c, d, e, F4, K4, M(75) );
+      R( e, a, b, c, d, F4, K4, M(76) );
+      R( d, e, a, b, c, F4, K4, M(77) );
+      R( c, d, e, a, b, F4, K4, M(78) );
+      R( b, c, d, e, a, F4, K4, M(79) );
+
+      a = ctx->A += a;
+      b = ctx->B += b;
+      c = ctx->C += c;
+      d = ctx->D += d;
+      e = ctx->E += e;
+    }
+}
diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/mdadm/sha1.h busybox-1.7.4+gentoo+mdadm/mdadm/sha1.h
--- busybox-1.7.4+gentoo/mdadm/sha1.h	1969-12-31 16:00:00.000000000 -0800
+++ busybox-1.7.4+gentoo+mdadm/mdadm/sha1.h	2008-03-11 10:31:00.000000000 -0700
@@ -0,0 +1,87 @@
+/* Declarations of functions and data types used for SHA1 sum
+   library functions.
+   Copyright (C) 2000, 2001, 2003, 2005 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any
+   later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#ifndef SHA1_H
+# define SHA1_H 1
+
+# include <stdio.h>
+# include "md5.h"
+
+/* Structure to save state of computation between the single steps.  */
+struct sha1_ctx
+{
+  md5_uint32 A;
+  md5_uint32 B;
+  md5_uint32 C;
+  md5_uint32 D;
+  md5_uint32 E;
+
+  md5_uint32 total[2];
+  md5_uint32 buflen;
+  char buffer[128] __attribute__ ((__aligned__ (__alignof__ (md5_uint32))));
+};
+
+
+/* Initialize structure containing state of computation. */
+extern void sha1_init_ctx (struct sha1_ctx *ctx);
+
+/* Starting with the result of former calls of this function (or the
+   initialization function update the context for the next LEN bytes
+   starting at BUFFER.
+   It is necessary that LEN is a multiple of 64!!! */
+extern void sha1_process_block (const void *buffer, size_t len,
+				struct sha1_ctx *ctx);
+
+/* Starting with the result of former calls of this function (or the
+   initialization function update the context for the next LEN bytes
+   starting at BUFFER.
+   It is NOT required that LEN is a multiple of 64.  */
+extern void sha1_process_bytes (const void *buffer, size_t len,
+				struct sha1_ctx *ctx);
+
+/* Process the remaining bytes in the buffer and put result from CTX
+   in first 20 bytes following RESBUF.  The result is always in little
+   endian byte order, so that a byte-wise output yields to the wanted
+   ASCII representation of the message digest.
+
+   IMPORTANT: On some systems it is required that RESBUF be correctly
+   aligned for a 32 bits value.  */
+extern void *sha1_finish_ctx (struct sha1_ctx *ctx, void *resbuf);
+
+
+/* Put result from CTX in first 20 bytes following RESBUF.  The result is
+   always in little endian byte order, so that a byte-wise output yields
+   to the wanted ASCII representation of the message digest.
+
+   IMPORTANT: On some systems it is required that RESBUF is correctly
+   aligned for a 32 bits value.  */
+extern void *sha1_read_ctx (const struct sha1_ctx *ctx, void *resbuf);
+
+
+/* Compute SHA1 message digest for bytes read from STREAM.  The
+   resulting message digest number will be written into the 20 bytes
+   beginning at RESBLOCK.  */
+extern int sha1_stream (FILE *stream, void *resblock);
+
+/* Compute SHA1 message digest for LEN bytes beginning at BUFFER.  The
+   result is always in little endian byte order, so that a byte-wise
+   output yields to the wanted ASCII representation of the message
+   digest.  */
+extern void *sha1_buffer (const char *buffer, size_t len, void *resblock);
+
+#endif
diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/mdadm/super0.c busybox-1.7.4+gentoo+mdadm/mdadm/super0.c
--- busybox-1.7.4+gentoo/mdadm/super0.c	1969-12-31 16:00:00.000000000 -0800
+++ busybox-1.7.4+gentoo+mdadm/mdadm/super0.c	2008-03-11 10:31:00.000000000 -0700
@@ -0,0 +1,562 @@
+/*
+ * mdadm - manage Linux "md" devices aka RAID arrays.
+ *
+ * Copyright (C) 2001-2006 Neil Brown <neilb@suse.de>
+ *
+ *
+ *    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
+ *
+ *    Author: Neil Brown
+ *    Email: <neilb@cse.unsw.edu.au>
+ *    Paper: Neil Brown
+ *           School of Computer Science and Engineering
+ *           The University of New South Wales
+ *           Sydney, 2052
+ *           Australia
+ */
+
+#define HAVE_STDINT_H 1
+#include "mdadm.h"
+/*
+ * All handling for the 0.90.0 version superblock is in
+ * this file.
+ * This includes:
+ *   - finding, loading, and writing the superblock.
+ *   - initialising a new superblock
+ *   - printing the superblock for --examine
+ *   - printing part of the superblock for --detail
+ * .. other stuff 
+ */
+
+
+static unsigned long calc_sb0_csum(mdp_super_t *super)
+{
+	unsigned long csum = super->sb_csum;
+	unsigned long newcsum;
+	super->sb_csum= 0 ;
+	newcsum = calc_csum(super, MD_SB_BYTES);
+	super->sb_csum = csum;
+	return newcsum;
+}
+
+
+void super0_swap_endian(struct mdp_superblock_s *sb)
+{
+	/* as super0 superblocks are host-endian, it is sometimes
+	 * useful to be able to swap the endianness 
+	 * as (almost) everything is u32's we byte-swap every 4byte
+	 * number.
+	 * We then also have to swap the events_hi and events_lo
+	 */
+	char *sbc = (char *)sb;
+	__u32 t32;
+	int i;
+
+	for (i=0; i < MD_SB_BYTES ; i+=4) {
+		char t = sbc[i];
+		sbc[i] = sbc[i+3];
+		sbc[i+3] = t;
+		t=sbc[i+1];
+		sbc[i+1]=sbc[i+2];
+		sbc[i+2]=t;
+	}
+	t32 = sb->events_hi;
+	sb->events_hi = sb->events_lo;
+	sb->events_lo = t32;
+
+	t32 = sb->cp_events_hi;
+	sb->cp_events_hi = sb->cp_events_lo;
+	sb->cp_events_lo = t32;
+
+}
+
+static void brief_examine_super0(void *sbv)
+{
+	mdp_super_t *sb = sbv;
+	char *c=map_num(pers, sb->level);
+	char devname[20];
+
+	sprintf(devname, "/dev/md%d", sb->md_minor);
+
+	printf("ARRAY %s level=%s num-devices=%d UUID=",
+	       devname,
+	       c?c:"-unknown-", sb->raid_disks);
+	if (sb->minor_version >= 90)
+		printf("%08x:%08x:%08x:%08x", sb->set_uuid0, sb->set_uuid1,
+		       sb->set_uuid2, sb->set_uuid3);
+	else
+		printf("%08x", sb->set_uuid0);
+	printf("\n");
+}
+
+static int match_home0(void *sbv, char *homehost)
+{
+	mdp_super_t *sb = sbv;
+	char buf[20];
+	char *hash = sha1_buffer(homehost,
+				 strlen(homehost),
+				 buf);
+
+	return (memcmp(&sb->set_uuid2, hash, 8)==0);
+}
+
+static void uuid_from_super0(int uuid[4], void * sbv)
+{
+	mdp_super_t *super = sbv;
+	uuid[0] = super->set_uuid0;
+	if (super->minor_version >= 90) {
+		uuid[1] = super->set_uuid1;
+		uuid[2] = super->set_uuid2;
+		uuid[3] = super->set_uuid3;
+	} else {
+		uuid[1] = 0;
+		uuid[2] = 0;
+		uuid[3] = 0;
+	}
+}
+
+static void getinfo_super0(struct mdinfo *info, void *sbv)
+{
+	mdp_super_t *sb = sbv;
+	int working = 0;
+	int i;
+
+	info->array.major_version = sb->major_version;
+	info->array.minor_version = sb->minor_version;
+	info->array.patch_version = sb->patch_version;
+	info->array.raid_disks = sb->raid_disks;
+	info->array.level = sb->level;
+	info->array.layout = sb->layout;
+	info->array.md_minor = sb->md_minor;
+	info->array.ctime = sb->ctime;
+	info->array.utime = sb->utime;
+	info->array.chunk_size = sb->chunk_size;
+	info->array.state = sb->state;
+	info->component_size = sb->size*2;
+
+	info->disk.state = sb->this_disk.state;
+	info->disk.major = sb->this_disk.major;
+	info->disk.minor = sb->this_disk.minor;
+	info->disk.raid_disk = sb->this_disk.raid_disk;
+	info->disk.number = sb->this_disk.number;
+
+	info->events = md_event(sb);
+	info->data_offset = 0;
+
+	uuid_from_super0(info->uuid, sbv);
+
+	if (sb->minor_version > 90 && (sb->reshape_position+1) != 0) {
+		info->reshape_active = 1;
+		info->reshape_progress = sb->reshape_position;
+		info->new_level = sb->new_level;
+		info->delta_disks = sb->delta_disks;
+		info->new_layout = sb->new_layout;
+		info->new_chunk = sb->new_chunk;
+	} else
+		info->reshape_active = 0;
+
+	sprintf(info->name, "%d", sb->md_minor);
+	/* work_disks is calculated rather than read directly */
+	for (i=0; i < MD_SB_DISKS; i++)
+		if ((sb->disks[i].state & (1<<MD_DISK_SYNC)) &&
+		    (sb->disks[i].raid_disk < info->array.raid_disks) &&
+		    (sb->disks[i].state & (1<<MD_DISK_ACTIVE)) &&
+		    !(sb->disks[i].state & (1<<MD_DISK_FAULTY)))
+			working ++;
+	info->array.working_disks = working;
+}
+
+
+static int update_super0(struct mdinfo *info, void *sbv, char *update,
+			 char *devname, int verbose,
+			 int uuid_set, char *homehost)
+{
+	/* NOTE: for 'assemble' and 'force' we need to return non-zero if any change was made.
+	 * For others, the return value is ignored.
+	 */
+	int rv = 0;
+	mdp_super_t *sb = sbv;
+	if (strcmp(update, "sparc2.2")==0 ) {
+		/* 2.2 sparc put the events in the wrong place
+		 * So we copy the tail of the superblock
+		 * up 4 bytes before continuing
+		 */
+		__u32 *sb32 = (__u32*)sb;
+		memcpy(sb32+MD_SB_GENERIC_CONSTANT_WORDS+7,
+		       sb32+MD_SB_GENERIC_CONSTANT_WORDS+7+1,
+		       (MD_SB_WORDS - (MD_SB_GENERIC_CONSTANT_WORDS+7+1))*4);
+		if (verbose >= 0)
+			fprintf (stderr, Name ": adjusting superblock of %s for 2.2/sparc compatability.\n",
+				 devname);
+	}
+	if (strcmp(update, "super-minor") ==0) {
+		sb->md_minor = info->array.md_minor;
+		if (verbose > 0)
+			fprintf(stderr, Name ": updating superblock of %s with minor number %d\n",
+				devname, info->array.md_minor);
+	}
+	if (strcmp(update, "summaries") == 0) {
+		int i;
+		/* set nr_disks, active_disks, working_disks,
+		 * failed_disks, spare_disks based on disks[] 
+		 * array in superblock.
+		 * Also make sure extra slots aren't 'failed'
+		 */
+		sb->nr_disks = sb->active_disks =
+			sb->working_disks = sb->failed_disks =
+			sb->spare_disks = 0;
+		for (i=0; i < MD_SB_DISKS ; i++) 
+			if (sb->disks[i].major ||
+			    sb->disks[i].minor) {
+				int state = sb->disks[i].state;
+				if (state & (1<<MD_DISK_REMOVED))
+					continue;
+				sb->nr_disks++;
+				if (state & (1<<MD_DISK_ACTIVE))
+					sb->active_disks++;
+				if (state & (1<<MD_DISK_FAULTY))
+					sb->failed_disks++;
+				else
+					sb->working_disks++;
+				if (state == 0)
+					sb->spare_disks++;
+			} else if (i >= sb->raid_disks && sb->disks[i].number == 0)
+				sb->disks[i].state = 0;
+	}
+	if (strcmp(update, "force-one")==0) {
+		/* Not enough devices for a working array, so
+		 * bring this one up-to-date.
+		 */
+		__u32 ehi = sb->events_hi, elo = sb->events_lo;
+		sb->events_hi = (info->events>>32) & 0xFFFFFFFF;
+		sb->events_lo = (info->events) & 0xFFFFFFFF;
+		if (sb->events_hi != ehi ||
+		    sb->events_lo != elo)
+			rv = 1;
+	}
+	if (strcmp(update, "force-array")==0) {
+		/* degraded array and 'force' requested, so
+		 * maybe need to mark it 'clean'
+		 */
+		if ((sb->level == 5 || sb->level == 4 || sb->level == 6) &&
+		    (sb->state & (1 << MD_SB_CLEAN)) == 0) {
+			/* need to force clean */
+			sb->state |= (1 << MD_SB_CLEAN);
+			rv = 1;
+		}
+	}
+	if (strcmp(update, "assemble")==0) {
+		int d = info->disk.number;
+		int wonly = sb->disks[d].state & (1<<MD_DISK_WRITEMOSTLY);
+		if ((sb->disks[d].state & ~(1<<MD_DISK_WRITEMOSTLY))
+		    != info->disk.state) {
+			sb->disks[d].state = info->disk.state | wonly;
+			rv = 1;
+		}
+	}
+	if (strcmp(update, "linear-grow-new") == 0) {
+		memset(&sb->disks[info->disk.number], 0, sizeof(sb->disks[0]));
+		sb->disks[info->disk.number].number = info->disk.number;
+		sb->disks[info->disk.number].major = info->disk.major;
+		sb->disks[info->disk.number].minor = info->disk.minor;
+		sb->disks[info->disk.number].raid_disk = info->disk.raid_disk;
+		sb->disks[info->disk.number].state = info->disk.state;
+		sb->this_disk = sb->disks[info->disk.number];
+	}
+	if (strcmp(update, "linear-grow-update") == 0) {
+		sb->raid_disks = info->array.raid_disks;
+		sb->nr_disks = info->array.nr_disks;
+		sb->active_disks = info->array.active_disks;
+		sb->working_disks = info->array.working_disks;
+		memset(&sb->disks[info->disk.number], 0, sizeof(sb->disks[0]));
+		sb->disks[info->disk.number].number = info->disk.number;
+		sb->disks[info->disk.number].major = info->disk.major;
+		sb->disks[info->disk.number].minor = info->disk.minor;
+		sb->disks[info->disk.number].raid_disk = info->disk.raid_disk;
+		sb->disks[info->disk.number].state = info->disk.state;
+	}
+	if (strcmp(update, "resync") == 0) {
+		/* make sure resync happens */
+		sb->state &= ~(1<<MD_SB_CLEAN);
+		sb->recovery_cp = 0;
+	}
+	if (strcmp(update, "homehost") == 0 &&
+	    homehost) {
+		uuid_set = 0;
+		update = "uuid";
+		info->uuid[0] = sb->set_uuid0;
+		info->uuid[1] = sb->set_uuid1;
+	}
+	if (strcmp(update, "uuid") == 0) {
+		if (!uuid_set && homehost) {
+			char buf[20];
+			char *hash = sha1_buffer(homehost,
+						 strlen(homehost),
+						 buf);
+			memcpy(info->uuid+2, hash, 8);
+		}
+		sb->set_uuid0 = info->uuid[0];
+		sb->set_uuid1 = info->uuid[1];
+		sb->set_uuid2 = info->uuid[2];
+		sb->set_uuid3 = info->uuid[3];
+		if (sb->state & (1<<MD_SB_BITMAP_PRESENT)) {
+			struct bitmap_super_s *bm;
+			bm = (struct bitmap_super_s*)(sb+1);
+			uuid_from_super0((int*)bm->uuid, sbv);
+		}
+	}
+	if (strcmp(update, "_reshape_progress")==0)
+		sb->reshape_position = info->reshape_progress;
+
+	sb->sb_csum = calc_sb0_csum(sb);
+	return rv;
+}
+
+static int store_super0(struct supertype *st, int fd, void *sbv)
+{
+	unsigned long long dsize;
+	unsigned long long offset;
+	mdp_super_t *super = sbv;
+
+	if (!get_dev_size(fd, NULL, &dsize))
+		return 1;
+
+	if (dsize < MD_RESERVED_SECTORS*2*512)
+		return 2;
+
+	offset = MD_NEW_SIZE_SECTORS(dsize>>9);
+
+	offset *= 512;
+
+	if (lseek64(fd, offset, 0)< 0LL)
+		return 3;
+
+	if (write(fd, super, sizeof(*super)) != sizeof(*super))
+		return 4;
+
+	if (super->state & (1<<MD_SB_BITMAP_PRESENT)) {
+		struct bitmap_super_s * bm = (struct bitmap_super_s*)(super+1);
+		if (__le32_to_cpu(bm->magic) == BITMAP_MAGIC)
+			if (write(fd, bm, sizeof(*bm)) != sizeof(*bm))
+			    return 5;
+	}
+
+	fsync(fd);
+	return 0;
+}
+
+static int compare_super0(void **firstp, void *secondv)
+{
+	/*
+	 * return:
+	 *  0 same, or first was empty, and second was copied
+	 *  1 second had wrong number
+	 *  2 wrong uuid
+	 *  3 wrong other info
+	 */
+	mdp_super_t *first = *firstp;
+	mdp_super_t *second = secondv;
+
+	int uuid1[4], uuid2[4];
+	if (second->md_magic != MD_SB_MAGIC)
+		return 1;
+	if (!first) {
+		first = malloc(MD_SB_BYTES + sizeof(struct bitmap_super_s));
+		memcpy(first, second, MD_SB_BYTES + sizeof(struct bitmap_super_s));
+		*firstp = first;
+		return 0;
+	}
+
+	uuid_from_super0(uuid1, first);
+	uuid_from_super0(uuid2, second);
+	if (!same_uuid(uuid1, uuid2, 0))
+		return 2;
+	if (first->major_version != second->major_version ||
+	    first->minor_version != second->minor_version ||
+	    first->patch_version != second->patch_version ||
+	    first->gvalid_words  != second->gvalid_words  ||
+	    first->ctime         != second->ctime         ||
+	    first->level         != second->level         ||
+	    first->size          != second->size          ||
+	    first->raid_disks    != second->raid_disks    )
+		return 3;
+
+	return 0;
+}
+
+
+static int load_super0(struct supertype *st, int fd, void **sbp, char *devname)
+{
+	/* try to read in the superblock
+	 * Return:
+	 *  0 on success
+	 *  1 on cannot get superblock
+	 *  2 on superblock meaningless
+	 */
+	unsigned long long dsize;
+	unsigned long long offset;
+	mdp_super_t *super;
+	int uuid[4];
+	struct bitmap_super_s *bsb;
+    
+	if (!get_dev_size(fd, devname, &dsize))
+		return 1;
+
+	if (dsize < MD_RESERVED_SECTORS*512 * 2) {
+		if (devname)
+			fprintf(stderr, Name
+			    ": %s is too small for md: size is %llu sectors.\n",
+				devname, dsize);
+		return 1;
+	}
+
+	offset = MD_NEW_SIZE_SECTORS(dsize>>9);
+
+	offset *= 512;
+
+	ioctl(fd, BLKFLSBUF, 0); /* make sure we read current data */
+
+	if (lseek64(fd, offset, 0)< 0LL) {
+		if (devname)
+			fprintf(stderr, Name ": Cannot seek to superblock on %s: %s\n",
+				devname, strerror(errno));
+		return 1;
+	}
+
+	super = malloc(MD_SB_BYTES + sizeof(bitmap_super_t));
+
+	if (read(fd, super, sizeof(*super)) != MD_SB_BYTES) {
+		if (devname)
+			fprintf(stderr, Name ": Cannot read superblock on %s\n",
+				devname);
+		free(super);
+		return 1;
+	}
+
+	if (st->ss && st->minor_version == 9)
+		super0_swap_endian(super);
+
+	if (super->md_magic != MD_SB_MAGIC) {
+		if (devname)
+			fprintf(stderr, Name ": No super block found on %s (Expected magic %08x, got %08x)\n",
+				devname, MD_SB_MAGIC, super->md_magic);
+		free(super);
+		return 2;
+	}
+
+	if (super->major_version != 0) {
+		if (devname)
+			fprintf(stderr, Name ": Cannot interpret superblock on %s - version is %d\n",
+				devname, super->major_version);
+		free(super);
+		return 2;
+	}
+	*sbp = super;
+	if (st->ss == NULL) {
+		st->ss = &super0;
+		st->minor_version = 90;
+		st->max_devs = MD_SB_DISKS;
+	}
+
+	/* Now check on the bitmap superblock */
+	if ((super->state & (1<<MD_SB_BITMAP_PRESENT)) == 0)
+		return 0;
+	/* Read the bitmap superblock and make sure it looks
+	 * valid.  If it doesn't clear the bit.  An --assemble --force
+	 * should get that written out.
+	 */
+	if (read(fd, super+1, sizeof(struct bitmap_super_s))
+	    != sizeof(struct bitmap_super_s))
+		goto no_bitmap;
+
+	uuid_from_super0(uuid, super);
+	bsb = (struct bitmap_super_s *)(super+1);
+	if (__le32_to_cpu(bsb->magic) != BITMAP_MAGIC ||
+	    memcmp(bsb->uuid, uuid, 16) != 0)
+		goto no_bitmap;
+	return 0;
+
+ no_bitmap:
+	super->state &= ~(1<<MD_SB_BITMAP_PRESENT);
+
+	return 0;
+}
+
+static struct supertype *match_metadata_desc0(char *arg)
+{
+	struct supertype *st = malloc(sizeof(*st));
+	if (!st) return st;
+
+	st->ss = &super0;
+	st->minor_version = 90;
+	st->max_devs = MD_SB_DISKS;
+	if (strcmp(arg, "0") == 0 ||
+	    strcmp(arg, "0.90") == 0 ||
+	    strcmp(arg, "default") == 0
+		)
+		return st;
+
+	st->minor_version = 9; /* flag for 'byte-swapped' */
+	if (strcmp(arg, "0.swap")==0)
+		return st;
+
+	free(st);
+	return NULL;
+}
+
+void locate_bitmap0(struct supertype *st, int fd, void *sbv)
+{
+	unsigned long long dsize;
+	unsigned long long offset;
+
+	if (!get_dev_size(fd, NULL, &dsize))
+		return;
+
+	if (dsize < MD_RESERVED_SECTORS*512 * 2)
+		return;
+
+	offset = MD_NEW_SIZE_SECTORS(dsize>>9);
+
+	offset *= 512;
+
+	offset += MD_SB_BYTES;
+
+	lseek64(fd, offset, 0);
+}
+
+struct superswitch super0 = {
+	.examine_super = NULL,
+	.brief_examine_super = brief_examine_super0,
+	.detail_super = NULL,
+	.brief_detail_super = NULL,
+	.export_super = NULL,
+	.match_home = match_home0,
+	.uuid_from_super = uuid_from_super0,
+	.getinfo_super = getinfo_super0,
+	.update_super = update_super0,
+	.init_super = NULL,
+	.add_to_super = NULL,
+	.store_super = store_super0,
+	.write_init_super = NULL,
+	.compare_super = compare_super0,
+	.load_super = load_super0,
+	.match_metadata_desc = match_metadata_desc0,
+	.avail_size = NULL,
+	.add_internal_bitmap = NULL, 
+	.locate_bitmap = locate_bitmap0,
+	.write_bitmap = NULL,
+	.major = 0,
+	.swapuuid = 0,
+};
diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/mdadm/super1.c busybox-1.7.4+gentoo+mdadm/mdadm/super1.c
--- busybox-1.7.4+gentoo/mdadm/super1.c	1969-12-31 16:00:00.000000000 -0800
+++ busybox-1.7.4+gentoo+mdadm/mdadm/super1.c	2008-03-11 10:31:00.000000000 -0700
@@ -0,0 +1,731 @@
+/*
+ * mdadm - manage Linux "md" devices aka RAID arrays.
+ *
+ * Copyright (C) 2001-2006 Neil Brown <neilb@suse.de>
+ *
+ *
+ *    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
+ *
+ *    Author: Neil Brown
+ *    Email: <neilb@cse.unsw.edu.au>
+ *    Paper: Neil Brown
+ *           School of Computer Science and Engineering
+ *           The University of New South Wales
+ *           Sydney, 2052
+ *           Australia
+ */
+
+#include "mdadm.h"
+/*
+ * The version-1 superblock :
+ * All numeric fields are little-endian.
+ *
+ * total size: 256 bytes plus 2 per device.
+ *  1K allows 384 devices.
+ */
+struct mdp_superblock_1 {
+	/* constant array information - 128 bytes */
+	__u32	magic;		/* MD_SB_MAGIC: 0xa92b4efc - little endian */
+	__u32	major_version;	/* 1 */
+	__u32	feature_map;	/* 0 for now */
+	__u32	pad0;		/* always set to 0 when writing */
+
+	__u8	set_uuid[16];	/* user-space generated. */
+	char	set_name[32];	/* set and interpreted by user-space */
+
+	__u64	ctime;		/* lo 40 bits are seconds, top 24 are microseconds or 0*/
+	__u32	level;		/* -4 (multipath), -1 (linear), 0,1,4,5 */
+	__u32	layout;		/* only for raid5 currently */
+	__u64	size;		/* used size of component devices, in 512byte sectors */
+
+	__u32	chunksize;	/* in 512byte sectors */
+	__u32	raid_disks;
+	__u32	bitmap_offset;	/* sectors after start of superblock that bitmap starts
+				 * NOTE: signed, so bitmap can be before superblock
+				 * only meaningful of feature_map[0] is set.
+				 */
+
+	/* These are only valid with feature bit '4' */
+	__u32	new_level;	/* new level we are reshaping to		*/
+	__u64	reshape_position;	/* next address in array-space for reshape */
+	__u32	delta_disks;	/* change in number of raid_disks		*/
+	__u32	new_layout;	/* new layout					*/
+	__u32	new_chunk;	/* new chunk size (bytes)			*/
+	__u8	pad1[128-124];	/* set to 0 when written */
+
+	/* constant this-device information - 64 bytes */
+	__u64	data_offset;	/* sector start of data, often 0 */
+	__u64	data_size;	/* sectors in this device that can be used for data */
+	__u64	super_offset;	/* sector start of this superblock */
+	__u64	recovery_offset;/* sectors before this offset (from data_offset) have been recovered */
+	__u32	dev_number;	/* permanent identifier of this  device - not role in raid */
+	__u32	cnt_corrected_read; /* number of read errors that were corrected by re-writing */
+	__u8	device_uuid[16]; /* user-space setable, ignored by kernel */
+        __u8    devflags;        /* per-device flags.  Only one defined...*/
+#define WriteMostly1    1        /* mask for writemostly flag in above */
+	__u8	pad2[64-57];	/* set to 0 when writing */
+
+	/* array state information - 64 bytes */
+	__u64	utime;		/* 40 bits second, 24 btes microseconds */
+	__u64	events;		/* incremented when superblock updated */
+	__u64	resync_offset;	/* data before this offset (from data_offset) known to be in sync */
+	__u32	sb_csum;	/* checksum upto devs[max_dev] */
+	__u32	max_dev;	/* size of devs[] array to consider */
+	__u8	pad3[64-32];	/* set to 0 when writing */
+
+	/* device state information. Indexed by dev_number.
+	 * 2 bytes per device
+	 * Note there are no per-device state flags. State information is rolled
+	 * into the 'roles' value.  If a device is spare or faulty, then it doesn't
+	 * have a meaningful role.
+	 */
+	__u16	dev_roles[0];	/* role in array, or 0xffff for a spare, or 0xfffe for faulty */
+};
+
+struct misc_dev_info {
+	__u64 device_size;
+};
+
+/* feature_map bits */
+#define MD_FEATURE_BITMAP_OFFSET	1
+#define	MD_FEATURE_RECOVERY_OFFSET	2 /* recovery_offset is present and
+					   * must be honoured
+					   */
+#define	MD_FEATURE_RESHAPE_ACTIVE	4
+
+#define	MD_FEATURE_ALL			(1|2|4)
+
+#ifndef offsetof
+#define offsetof(t,f) ((size_t)&(((t*)0)->f))
+#endif
+static unsigned int calc_sb_1_csum(struct mdp_superblock_1 * sb)
+{
+	unsigned int disk_csum, csum;
+	unsigned long long newcsum;
+	int size = sizeof(*sb) + __le32_to_cpu(sb->max_dev)*2;
+	unsigned int *isuper = (unsigned int*)sb;
+	int i;
+
+/* make sure I can count... */
+	if (offsetof(struct mdp_superblock_1,data_offset) != 128 ||
+	    offsetof(struct mdp_superblock_1, utime) != 192 ||
+	    sizeof(struct mdp_superblock_1) != 256) {
+		fprintf(stderr, "WARNING - superblock isn't sized correctly\n");
+	}
+
+	disk_csum = sb->sb_csum;
+	sb->sb_csum = 0;
+	newcsum = 0;
+	for (i=0; size>=4; size -= 4 ) {
+		newcsum += __le32_to_cpu(*isuper);
+		isuper++;
+	}
+
+	if (size == 2)
+		newcsum += __le16_to_cpu(*(unsigned short*) isuper);
+
+	csum = (newcsum & 0xffffffff) + (newcsum >> 32);
+	sb->sb_csum = disk_csum;
+	return __cpu_to_le32(csum);
+}
+
+static void brief_examine_super1(void *sbv)
+{
+	struct mdp_superblock_1 *sb = sbv;
+	int i;
+	unsigned long long sb_offset;
+	char *nm;
+	char *c=map_num(pers, __le32_to_cpu(sb->level));
+
+	nm = strchr(sb->set_name, ':');
+	if (nm)
+		nm++;
+	else if (sb->set_name[0])
+		nm = sb->set_name;
+	else
+		nm = "??";
+
+	printf("ARRAY /dev/md%s level=%s ", nm, c?c:"-unknown-");
+	sb_offset = __le64_to_cpu(sb->super_offset);
+	if (sb_offset <= 4)
+		printf("metadata=1.1 ");
+	else if (sb_offset <= 8)
+		printf("metadata=1.2 ");
+	else
+		printf("metadata=1.0 ");
+	printf("num-devices=%d UUID=", __le32_to_cpu(sb->raid_disks));
+	for (i=0; i<16; i++) {
+		if ((i&3)==0 && i != 0) printf(":");
+		printf("%02x", sb->set_uuid[i]);
+	}
+	if (sb->set_name[0])
+		printf(" name=%.32s", sb->set_name);
+	printf("\n");
+}
+
+static int match_home1(void *sbv, char *homehost)
+{
+	struct mdp_superblock_1 *sb = sbv;
+	int l = homehost ? strlen(homehost) : 0;
+
+	return (l > 0 && l < 32 &&
+		sb->set_name[l] == ':' &&
+		strncmp(sb->set_name, homehost, l) == 0);
+}
+
+static void uuid_from_super1(int uuid[4], void * sbv)
+{
+	struct mdp_superblock_1 *super = sbv;
+	char *cuuid = (char*)uuid;
+	int i;
+	for (i=0; i<16; i++)
+		cuuid[i] = super->set_uuid[i];
+}
+
+static void getinfo_super1(struct mdinfo *info, void *sbv)
+{
+	struct mdp_superblock_1 *sb = sbv;
+	int working = 0;
+	int i;
+	int role;
+
+	info->array.major_version = 1;
+	info->array.minor_version = __le32_to_cpu(sb->feature_map);
+	info->array.patch_version = 0;
+	info->array.raid_disks = __le32_to_cpu(sb->raid_disks);
+	info->array.level = __le32_to_cpu(sb->level);
+	info->array.layout = __le32_to_cpu(sb->layout);
+	info->array.md_minor = -1;
+	info->array.ctime = __le64_to_cpu(sb->ctime);
+	info->array.utime = __le64_to_cpu(sb->utime);
+	info->array.chunk_size = __le32_to_cpu(sb->chunksize)*512;
+	info->array.state =
+		(__le64_to_cpu(sb->resync_offset) >= __le64_to_cpu(sb->size))
+		? 1 : 0;
+
+	info->data_offset = __le64_to_cpu(sb->data_offset);
+	info->component_size = __le64_to_cpu(sb->size);
+
+	info->disk.major = 0;
+	info->disk.minor = 0;
+	info->disk.number = __le32_to_cpu(sb->dev_number);
+	if (__le32_to_cpu(sb->dev_number) >= __le32_to_cpu(sb->max_dev) ||
+	    __le32_to_cpu(sb->max_dev) > 512)
+		role = 0xfffe;
+	else
+		role = __le16_to_cpu(sb->dev_roles[__le32_to_cpu(sb->dev_number)]);
+
+	info->disk.raid_disk = -1;
+	switch(role) {
+	case 0xFFFF:
+		info->disk.state = 2; /* spare: ACTIVE, not sync, not faulty */
+		break;
+	case 0xFFFE:
+		info->disk.state = 1; /* faulty */
+		break;
+	default:
+		info->disk.state = 6; /* active and in sync */
+		info->disk.raid_disk = role;
+	}
+	info->events = __le64_to_cpu(sb->events);
+
+	memcpy(info->uuid, sb->set_uuid, 16);
+
+	strncpy(info->name, sb->set_name, 32);
+	info->name[32] = 0;
+
+	if (sb->feature_map & __le32_to_cpu(MD_FEATURE_RESHAPE_ACTIVE)) {
+		info->reshape_active = 1;
+		info->reshape_progress = __le64_to_cpu(sb->reshape_position);
+		info->new_level = __le32_to_cpu(sb->new_level);
+		info->delta_disks = __le32_to_cpu(sb->delta_disks);
+		info->new_layout = __le32_to_cpu(sb->new_layout);
+		info->new_chunk = __le32_to_cpu(sb->new_chunk)<<9;
+	} else
+		info->reshape_active = 0;
+
+	for (i=0; i< __le32_to_cpu(sb->max_dev); i++) {
+		role = __le16_to_cpu(sb->dev_roles[i]);
+		if (/*role == 0xFFFF || */role < info->array.raid_disks)
+			working++;
+	}
+
+	info->array.working_disks = working;
+}
+
+static int update_super1(struct mdinfo *info, void *sbv, char *update,
+			 char *devname, int verbose,
+			 int uuid_set, char *homehost)
+{
+	/* NOTE: for 'assemble' and 'force' we need to return non-zero if any change was made.
+	 * For others, the return value is ignored.
+	 */
+	int rv = 0;
+	struct mdp_superblock_1 *sb = sbv;
+
+	if (strcmp(update, "force-one")==0) {
+		/* Not enough devices for a working array,
+		 * so bring this one up-to-date
+		 */
+		if (sb->events != __cpu_to_le64(info->events))
+			rv = 1;
+		sb->events = __cpu_to_le64(info->events);
+	}
+	if (strcmp(update, "force-array")==0) {
+		/* Degraded array and 'force' requests to
+		 * maybe need to mark it 'clean'.
+		 */
+		switch(__le32_to_cpu(sb->level)) {
+		case 5: case 4: case 6:
+			/* need to force clean */
+			if (sb->resync_offset != ~0ULL)
+				rv = 1;
+			sb->resync_offset = ~0ULL;
+		}
+	}
+	if (strcmp(update, "assemble")==0) {
+		int d = info->disk.number;
+		int want;
+		if (info->disk.state == 6)
+			want = __cpu_to_le32(info->disk.raid_disk);
+		else
+			want = 0xFFFF;
+		if (sb->dev_roles[d] != want) {
+			sb->dev_roles[d] = want;
+			rv = 1;
+		}
+	}
+	if (strcmp(update, "linear-grow-new") == 0) {
+		int i;
+		int rfd;
+		int max = __le32_to_cpu(sb->max_dev);
+
+		for (i=0 ; i < max ; i++)
+			if (__le16_to_cpu(sb->dev_roles[i]) >= 0xfffe)
+				break;
+		sb->dev_number = __cpu_to_le32(i);
+		info->disk.number = i;
+		if (max >= __le32_to_cpu(sb->max_dev))
+			sb->max_dev = __cpu_to_le32(max+1);
+
+		if ((rfd = open("/dev/urandom", O_RDONLY)) < 0 ||
+		    read(rfd, sb->device_uuid, 16) != 16) {
+			*(__u32*)(sb->device_uuid) = random();
+			*(__u32*)(sb->device_uuid+4) = random();
+			*(__u32*)(sb->device_uuid+8) = random();
+			*(__u32*)(sb->device_uuid+12) = random();
+		}
+
+		sb->dev_roles[i] =
+			__cpu_to_le16(info->disk.raid_disk);
+	}
+	if (strcmp(update, "linear-grow-update") == 0) {
+		sb->raid_disks = __cpu_to_le32(info->array.raid_disks);
+		sb->dev_roles[info->disk.number] =
+			__cpu_to_le16(info->disk.raid_disk);
+	}
+	if (strcmp(update, "resync") == 0) {
+		/* make sure resync happens */
+		sb->resync_offset = 0ULL;
+	}
+	if (strcmp(update, "uuid") == 0) {
+		copy_uuid(sb->set_uuid, info->uuid, super1.swapuuid);
+
+		if (__le32_to_cpu(sb->feature_map)&MD_FEATURE_BITMAP_OFFSET) {
+			struct bitmap_super_s *bm;
+			bm = (struct bitmap_super_s*)(sbv+1024);
+			memcpy(bm->uuid, sb->set_uuid, 16);
+		}
+	}
+	if (strcmp(update, "homehost") == 0 &&
+	    homehost) {
+		char *c;
+		update = "name";
+		c = strchr(sb->set_name, ':');
+		if (c)
+			strncpy(info->name, c+1, 31 - (c-sb->set_name));
+		else
+			strncpy(info->name, sb->set_name, 32);
+		info->name[32] = 0;
+	}
+	if (strcmp(update, "name") == 0) {
+		if (info->name[0] == 0)
+			sprintf(info->name, "%d", info->array.md_minor);
+		memset(sb->set_name, 0, sizeof(sb->set_name));
+		if (homehost &&
+		    strchr(info->name, ':') == NULL &&
+		    strlen(homehost)+1+strlen(info->name) < 32) {
+			strcpy(sb->set_name, homehost);
+			strcat(sb->set_name, ":");
+			strcat(sb->set_name, info->name);
+		} else
+			strcpy(sb->set_name, info->name);
+	}
+	if (strcmp(update, "devicesize") == 0 &&
+	    __le64_to_cpu(sb->super_offset) <
+	    __le64_to_cpu(sb->data_offset)) {
+		/* set data_size to device size less data_offset */
+		struct misc_dev_info *misc = (struct misc_dev_info*)
+			(sbv + 1024 + sizeof(struct bitmap_super_s));
+		printf("Size was %llu\n", (unsigned long long)
+		       __le64_to_cpu(sb->data_size));
+		sb->data_size = __cpu_to_le64(
+			misc->device_size - __le64_to_cpu(sb->data_offset));
+		printf("Size is %llu\n", (unsigned long long)
+		       __le64_to_cpu(sb->data_size));
+	}
+	if (strcmp(update, "_reshape_progress")==0)
+		sb->reshape_position = __cpu_to_le64(info->reshape_progress);
+
+	sb->sb_csum = calc_sb_1_csum(sb);
+	return rv;
+}
+
+static void locate_bitmap1(struct supertype *st, int fd, void *sbv);
+
+static int store_super1(struct supertype *st, int fd, void *sbv)
+{
+	struct mdp_superblock_1 *sb = sbv;
+	unsigned long long sb_offset;
+	int sbsize;
+	unsigned long long dsize;
+
+	if (!get_dev_size(fd, NULL, &dsize))
+		return 1;
+
+	dsize >>= 9;
+
+	if (dsize < 24)
+		return 2;
+
+	/*
+	 * Calculate the position of the superblock.
+	 * It is always aligned to a 4K boundary and
+	 * depending on minor_version, it can be:
+	 * 0: At least 8K, but less than 12K, from end of device
+	 * 1: At start of device
+	 * 2: 4K from start of device.
+	 */
+	switch(st->minor_version) {
+	case 0:
+		sb_offset = dsize;
+		sb_offset -= 8*2;
+		sb_offset &= ~(4*2-1);
+		break;
+	case 1:
+		sb_offset = 0;
+		break;
+	case 2:
+		sb_offset = 4*2;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+
+
+	if (sb_offset != __le64_to_cpu(sb->super_offset) &&
+	    0 != __le64_to_cpu(sb->super_offset)
+		) {
+		fprintf(stderr, Name ": internal error - sb_offset is wrong\n");
+		abort();
+	}
+
+	if (lseek64(fd, sb_offset << 9, 0)< 0LL)
+		return 3;
+
+	sbsize = sizeof(*sb) + 2 * __le32_to_cpu(sb->max_dev);
+
+	if (write(fd, sb, sbsize) != sbsize)
+		return 4;
+
+	if (sb->feature_map & __cpu_to_le32(MD_FEATURE_BITMAP_OFFSET)) {
+		struct bitmap_super_s *bm = (struct bitmap_super_s*)
+			(((char*)sb)+1024);
+		if (__le32_to_cpu(bm->magic) == BITMAP_MAGIC) {
+			locate_bitmap1(st, fd, sbv);
+			if (write(fd, bm, sizeof(*bm)) != sizeof(*bm))
+			    return 5;
+		}
+	}
+	fsync(fd);
+	return 0;
+}
+
+static int load_super1(struct supertype *st, int fd, void **sbp, char *devname);
+
+static int compare_super1(void **firstp, void *secondv)
+{
+	/*
+	 * return:
+	 *  0 same, or first was empty, and second was copied
+	 *  1 second had wrong number
+	 *  2 wrong uuid
+	 *  3 wrong other info
+	 */
+	struct mdp_superblock_1 *first = *firstp;
+	struct mdp_superblock_1 *second = secondv;
+
+	if (second->magic != __cpu_to_le32(MD_SB_MAGIC))
+		return 1;
+	if (second->major_version != __cpu_to_le32(1))
+		return 1;
+
+	if (!first) {
+		first = malloc(1024+sizeof(bitmap_super_t) +
+			       sizeof(struct misc_dev_info));
+		memcpy(first, second, 1024+sizeof(bitmap_super_t) +
+		       sizeof(struct misc_dev_info));
+		*firstp = first;
+		return 0;
+	}
+	if (memcmp(first->set_uuid, second->set_uuid, 16)!= 0)
+		return 2;
+
+	if (first->ctime      != second->ctime     ||
+	    first->level      != second->level     ||
+	    first->layout     != second->layout    ||
+	    first->size       != second->size      ||
+	    first->chunksize  != second->chunksize ||
+	    first->raid_disks != second->raid_disks)
+		return 3;
+	return 0;
+}
+
+static int load_super1(struct supertype *st, int fd, void **sbp, char *devname)
+{
+	unsigned long long dsize;
+	unsigned long long sb_offset;
+	struct mdp_superblock_1 *super;
+	int uuid[4];
+	struct bitmap_super_s *bsb;
+	struct misc_dev_info *misc;
+
+
+	if (st->ss == NULL) {
+		int bestvers = -1;
+		__u64 bestctime = 0;
+		/* guess... choose latest ctime */
+		st->ss = &super1;
+		for (st->minor_version = 0; st->minor_version <= 2 ; st->minor_version++) {
+			switch(load_super1(st, fd, sbp, devname)) {
+			case 0: super = *sbp;
+				if (bestvers == -1 ||
+				    bestctime < __le64_to_cpu(super->ctime)) {
+					bestvers = st->minor_version;
+					bestctime = __le64_to_cpu(super->ctime);
+				}
+				free(super);
+				*sbp = NULL;
+				break;
+			case 1: st->ss = NULL; return 1; /*bad device */
+			case 2: break; /* bad, try next */
+			}
+		}
+		if (bestvers != -1) {
+			int rv;
+			st->minor_version = bestvers;
+			st->ss = &super1;
+			st->max_devs = 384;
+			rv = load_super1(st, fd, sbp, devname);
+			if (rv) st->ss = NULL;
+			return rv;
+		}
+		st->ss = NULL;
+		return 2;
+	}
+	if (!get_dev_size(fd, devname, &dsize))
+		return 1;
+	dsize >>= 9;
+
+	if (dsize < 24) {
+		if (devname)
+			fprintf(stderr, Name ": %s is too small for md: size is %llu sectors.\n",
+				devname, dsize);
+		return 1;
+	}
+
+	/*
+	 * Calculate the position of the superblock.
+	 * It is always aligned to a 4K boundary and
+	 * depending on minor_version, it can be:
+	 * 0: At least 8K, but less than 12K, from end of device
+	 * 1: At start of device
+	 * 2: 4K from start of device.
+	 */
+	switch(st->minor_version) {
+	case 0:
+		sb_offset = dsize;
+		sb_offset -= 8*2;
+		sb_offset &= ~(4*2-1);
+		break;
+	case 1:
+		sb_offset = 0;
+		break;
+	case 2:
+		sb_offset = 4*2;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ioctl(fd, BLKFLSBUF, 0); /* make sure we read current data */
+
+
+	if (lseek64(fd, sb_offset << 9, 0)< 0LL) {
+		if (devname)
+			fprintf(stderr, Name ": Cannot seek to superblock on %s: %s\n",
+				devname, strerror(errno));
+		return 1;
+	}
+
+	super = malloc(1024 + sizeof(bitmap_super_t) +
+		       sizeof(struct misc_dev_info));
+
+	if (read(fd, super, 1024) != 1024) {
+		if (devname)
+			fprintf(stderr, Name ": Cannot read superblock on %s\n",
+				devname);
+		free(super);
+		return 1;
+	}
+
+	if (__le32_to_cpu(super->magic) != MD_SB_MAGIC) {
+		if (devname)
+			fprintf(stderr, Name ": No super block found on %s (Expected magic %08x, got %08x)\n",
+				devname, MD_SB_MAGIC, __le32_to_cpu(super->magic));
+		free(super);
+		return 2;
+	}
+
+	if (__le32_to_cpu(super->major_version) != 1) {
+		if (devname)
+			fprintf(stderr, Name ": Cannot interpret superblock on %s - version is %d\n",
+				devname, __le32_to_cpu(super->major_version));
+		free(super);
+		return 2;
+	}
+	if (__le64_to_cpu(super->super_offset) != sb_offset) {
+		if (devname)
+			fprintf(stderr, Name ": No superblock found on %s (super_offset is wrong)\n",
+				devname);
+		free(super);
+		return 2;
+	}
+	*sbp = super;
+
+	bsb = (struct bitmap_super_s *)(((char*)super)+1024);
+
+	misc = (struct misc_dev_info*) (bsb+1);
+	misc->device_size = dsize;
+
+	/* Now check on the bitmap superblock */
+	if ((__le32_to_cpu(super->feature_map)&MD_FEATURE_BITMAP_OFFSET) == 0)
+		return 0;
+	/* Read the bitmap superblock and make sure it looks
+	 * valid.  If it doesn't clear the bit.  An --assemble --force
+	 * should get that written out.
+	 */
+	locate_bitmap1(st, fd, super);
+	if (read(fd, ((char*)super)+1024, sizeof(struct bitmap_super_s))
+	    != sizeof(struct bitmap_super_s))
+		goto no_bitmap;
+
+	uuid_from_super1(uuid, super);
+	if (__le32_to_cpu(bsb->magic) != BITMAP_MAGIC ||
+	    memcmp(bsb->uuid, uuid, 16) != 0)
+		goto no_bitmap;
+	return 0;
+
+ no_bitmap:
+	super->feature_map = __cpu_to_le32(__le32_to_cpu(super->feature_map) & ~1);
+	return 0;
+}
+
+
+static struct supertype *match_metadata_desc1(char *arg)
+{
+	struct supertype *st = malloc(sizeof(*st));
+	if (!st) return st;
+
+	st->ss = &super1;
+	st->max_devs = 384;
+	if (strcmp(arg, "1") == 0 ||
+	    strcmp(arg, "1.0") == 0 ||
+	    strcmp(arg, "default/large") == 0) {
+		st->minor_version = 0;
+		return st;
+	}
+	if (strcmp(arg, "1.1") == 0) {
+		st->minor_version = 1;
+		return st;
+	}
+	if (strcmp(arg, "1.2") == 0) {
+		st->minor_version = 2;
+		return st;
+	}
+
+	free(st);
+	return NULL;
+}
+
+static void locate_bitmap1(struct supertype *st, int fd, void *sbv)
+{
+	unsigned long long offset;
+	struct mdp_superblock_1 *sb;
+	int mustfree = 0;
+
+	if (!sbv) {
+		if (st->ss->load_super(st, fd, &sbv, NULL))
+			return; /* no error I hope... */
+		mustfree = 1;
+	}
+	sb = sbv;
+
+	offset = __le64_to_cpu(sb->super_offset);
+	offset += (int32_t) __le32_to_cpu(sb->bitmap_offset);
+	if (mustfree)
+		free(sb);
+	lseek64(fd, offset<<9, 0);
+}
+
+struct superswitch super1 = {
+	.examine_super = NULL,
+	.brief_examine_super = brief_examine_super1,
+	.detail_super = NULL,
+	.brief_detail_super = NULL,
+	.export_super = NULL,
+	.match_home = match_home1,
+	.uuid_from_super = uuid_from_super1,
+	.getinfo_super = getinfo_super1,
+	.update_super = update_super1,
+	.init_super = NULL,
+	.add_to_super = NULL,
+	.store_super = store_super1,
+	.write_init_super = NULL,
+	.compare_super = compare_super1,
+	.load_super = load_super1,
+	.match_metadata_desc = match_metadata_desc1,
+	.avail_size = NULL,
+	.add_internal_bitmap = NULL,
+	.locate_bitmap = locate_bitmap1,
+	.write_bitmap = NULL,
+	.major = 1,
+#if __BYTE_ORDER == BIG_ENDIAN
+	.swapuuid = 0,
+#else
+	.swapuuid = 1,
+#endif
+};
diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/mdadm/util.c busybox-1.7.4+gentoo+mdadm/mdadm/util.c
--- busybox-1.7.4+gentoo/mdadm/util.c	1969-12-31 16:00:00.000000000 -0800
+++ busybox-1.7.4+gentoo+mdadm/mdadm/util.c	2008-03-11 10:31:00.000000000 -0700
@@ -0,0 +1,652 @@
+/*
+ * mdadm - manage Linux "md" devices aka RAID arrays.
+ *
+ * Copyright (C) 2001-2006 Neil Brown <neilb@suse.de>
+ *
+ *
+ *    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
+ *
+ *    Author: Neil Brown
+ *    Email: <neilb@cse.unsw.edu.au>
+ *    Paper: Neil Brown
+ *           School of Computer Science and Engineering
+ *           The University of New South Wales
+ *           Sydney, 2052
+ *           Australia
+ */
+
+#include	"mdadm.h"
+#include	"md_p.h"
+#include	<sys/utsname.h>
+#include	<ctype.h>
+
+/*
+ * following taken from linux/blkpg.h because they aren't
+ * anywhere else and it isn't safe to #include linux/ * stuff.
+ */
+
+#define BLKPG      _IO(0x12,105)
+
+/* The argument structure */
+struct blkpg_ioctl_arg {
+        int op;
+        int flags;
+        int datalen;
+        void *data;
+};
+
+/* The subfunctions (for the op field) */
+#define BLKPG_ADD_PARTITION	1
+#define BLKPG_DEL_PARTITION	2
+
+/* Sizes of name fields. Unused at present. */
+#define BLKPG_DEVNAMELTH	64
+#define BLKPG_VOLNAMELTH	64
+
+/* The data structure for ADD_PARTITION and DEL_PARTITION */
+struct blkpg_partition {
+	long long start;		/* starting offset in bytes */
+	long long length;		/* length in bytes */
+	int pno;			/* partition number */
+	char devname[BLKPG_DEVNAMELTH];	/* partition name, like sda5 or c0d1p2,
+					   to be used in kernel messages */
+	char volname[BLKPG_VOLNAMELTH];	/* volume label */
+};
+
+/*
+ * Parse a 128 bit uuid in 4 integers
+ * format is 32 hexx nibbles with options :.<space> separator
+ * If not exactly 32 hex digits are found, return 0
+ * else return 1
+ */
+int parse_uuid(char *str, int uuid[4])
+{
+    int hit = 0; /* number of Hex digIT */
+    int i;
+    char c;
+    for (i=0; i<4; i++) uuid[i]=0;
+
+    while ((c= *str++)) {
+	int n;
+	if (c>='0' && c<='9')
+	    n = c-'0';
+	else if (c>='a' && c <= 'f')
+	    n = 10 + c - 'a';
+	else if (c>='A' && c <= 'F')
+	    n = 10 + c - 'A';
+	else if (strchr(":. -", c))
+	    continue;
+	else return 0;
+
+	if (hit<32) {
+	    uuid[hit/8] <<= 4;
+	    uuid[hit/8] += n;
+	}
+	hit++;
+    }
+    if (hit == 32)
+	return 1;
+    return 0;
+    
+}
+
+
+/*
+ * Get the md version number.
+ * We use the RAID_VERSION ioctl if it is supported
+ * If not, but we have a block device with major '9', we assume
+ * 0.36.0
+ *
+ * Return version number as 24 but number - assume version parts
+ * always < 255
+ */
+
+int md_get_version(int fd)
+{
+    struct stat stb;
+    mdu_version_t vers;
+
+    if (fstat(fd, &stb)<0)
+	return -1;
+    if ((S_IFMT&stb.st_mode) != S_IFBLK)
+	return -1;
+
+    if (ioctl(fd, RAID_VERSION, &vers) == 0)
+	return  (vers.major*10000) + (vers.minor*100) + vers.patchlevel;
+    if (errno == EACCES)
+	    return -1;
+    if (major(stb.st_rdev) == MD_MAJOR)
+	return (3600);
+    return -1;
+}
+
+    
+int get_linux_version()
+{
+	struct utsname name;
+	char *cp;
+	int a,b,c;
+	if (uname(&name) <0)
+		return -1;
+
+	cp = name.release;
+	a = strtoul(cp, &cp, 10);
+	if (*cp != '.') return -1;
+	b = strtoul(cp+1, &cp, 10);
+	if (*cp != '.') return -1;
+	c = strtoul(cp+1, NULL, 10);
+
+	return (a*1000000)+(b*1000)+c;
+}
+
+void remove_partitions(int fd)
+{
+	/* remove partitions from this block devices.
+	 * This is used for components added to an array
+	 */
+#ifdef BLKPG_DEL_PARTITION
+	struct blkpg_ioctl_arg a;
+	struct blkpg_partition p;
+
+	a.op = BLKPG_DEL_PARTITION;
+	a.data = (void*)&p;
+	a.datalen = sizeof(p);
+	a.flags = 0;
+	memset(a.data, 0, a.datalen);
+	for (p.pno=0; p.pno < 16; p.pno++)
+		ioctl(fd, BLKPG, &a);
+#endif
+}
+
+int enough(int level, int raid_disks, int layout, int clean,
+	   char *avail, int avail_disks)
+{
+	int copies, first;
+	switch (level) {
+	case 10:
+		/* This is the tricky one - we need to check
+		 * which actual disks are present.
+		 */
+		copies = (layout&255)* ((layout>>8) & 255);
+		first=0;
+		do {
+			/* there must be one of the 'copies' form 'first' */
+			int n = copies;
+			int cnt=0;
+			while (n--) {
+				if (avail[first])
+					cnt++;
+				first = (first+1) % raid_disks;
+			}
+			if (cnt == 0)
+				return 0;
+
+		} while (first != 0);
+		return 1;
+
+	case -4:
+		return avail_disks>= 1;
+	case -1:
+	case 0:
+		return avail_disks == raid_disks;
+	case 1:
+		return avail_disks >= 1;
+	case 4:
+	case 5:
+		if (clean)
+			return avail_disks >= raid_disks-1;
+		else
+			return avail_disks >= raid_disks;
+	case 6:
+		if (clean)
+			return avail_disks >= raid_disks-2;
+		else
+			return avail_disks >= raid_disks;
+	default:
+		return 0;
+	}
+}
+
+int same_uuid(int a[4], int b[4], int swapuuid)
+{
+	if (swapuuid) {
+		/* parse uuids are hostendian.
+		 * uuid's from some superblocks are big-ending
+		 * if there is a difference, we need to swap.. 
+		 */
+		unsigned char *ac = (unsigned char *)a;
+		unsigned char *bc = (unsigned char *)b;
+		int i;
+		for (i=0; i<16; i+= 4) {
+			if (ac[i+0] != bc[i+3] ||
+			    ac[i+1] != bc[i+2] ||
+			    ac[i+2] != bc[i+1] ||
+			    ac[i+3] != bc[i+0])
+				return 0;
+		}
+		return 1;
+	} else {
+		if (a[0]==b[0] &&
+		    a[1]==b[1] &&
+		    a[2]==b[2] &&
+		    a[3]==b[3])
+			return 1;
+		return 0;
+	}
+}
+void copy_uuid(void *a, int b[4], int swapuuid)
+{
+	if (swapuuid) {
+		/* parse uuids are hostendian.
+		 * uuid's from some superblocks are big-ending
+		 * if there is a difference, we need to swap..
+		 */
+		unsigned char *ac = (unsigned char *)a;
+		unsigned char *bc = (unsigned char *)b;
+		int i;
+		for (i=0; i<16; i+= 4) {
+			ac[i+0] = bc[i+3];
+			ac[i+1] = bc[i+2];
+			ac[i+2] = bc[i+1];
+			ac[i+3] = bc[i+0];
+		}
+	} else
+		memcpy(a, b, 16);
+}
+
+char *map_num(mapping_t *map, int num)
+{
+	while (map->name) {
+		if (map->num == num)
+			return map->name;
+		map++;
+	}
+	return NULL;
+}
+
+int map_name(mapping_t *map, char *name)
+{
+	while (map->name) {
+		if (strcmp(map->name, name)==0)
+			return map->num;
+		map++;
+	}
+	return UnSet;
+}
+
+
+int is_standard(char *dev, int *nump)
+{
+	/* tests if dev is a "standard" md dev name.
+	 * i.e if the last component is "/dNN" or "/mdNN",
+	 * where NN is a string of digits 
+	 */
+	char *d = strrchr(dev, '/');
+	int type=0;
+	int num;
+	if (!d)
+		return 0;
+	if (strncmp(d, "/d",2)==0)
+		d += 2, type=1; /* /dev/md/dN{pM} */
+	else if (strncmp(d, "/md_d", 5)==0)
+		d += 5, type=1; /* /dev/md_dNpM */
+	else if (strncmp(d, "/md", 3)==0)
+		d += 3, type=-1; /* /dev/mdN */
+	else if (d-dev > 3 && strncmp(d-2, "md/", 3)==0)
+		d += 1, type=-1; /* /dev/md/N */
+	else
+		return 0;
+	if (!*d)
+		return 0;
+	num = atoi(d);
+	while (isdigit(*d))
+		d++;
+	if (*d)
+		return 0;
+	if (nump) *nump = num;
+
+	return type;
+}
+
+
+/*
+ * convert a major/minor pair for a block device into a name in /dev, if possible.
+ * On the first call, walk /dev collecting name.
+ * Put them in a simple linked listfor now.
+ */
+struct devmap {
+    int major, minor;
+    char *name;
+    struct devmap *next;
+} *devlist = NULL;
+int devlist_ready = 0;
+
+int add_dev(const char *name, const struct stat *stb, int flag, struct FTW *s)
+{
+	struct stat st;
+	if (S_ISLNK(stb->st_mode)) {
+		stat(name, &st);
+		stb = &st;
+	}
+
+	if ((stb->st_mode&S_IFMT)== S_IFBLK) {
+		char *n = strdup(name);
+		struct devmap *dm = malloc(sizeof(*dm));
+		if (strncmp(n, "/dev/./", 7)==0)
+			strcpy(n+4, name+6);
+		if (dm) {
+			dm->major = major(stb->st_rdev);
+			dm->minor = minor(stb->st_rdev);
+			dm->name = n;
+			dm->next = devlist;
+			devlist = dm;
+		}
+	}
+	return 0;
+}
+
+#ifndef HAVE_NFTW
+#ifdef HAVE_FTW
+int add_dev_1(const char *name, const struct stat *stb, int flag)
+{
+	return add_dev(name, stb, flag, NULL);
+}
+int nftw(const char *path, int (*han)(const char *name, const struct stat *stb, int flag, struct FTW *s), int nopenfd, int flags)
+{
+	return ftw(path, add_dev_1, nopenfd);
+}
+#else
+int nftw(const char *path, int (*han)(const char *name, const struct stat *stb, int flag, struct FTW *s), int nopenfd, int flags)
+{
+	return 0;
+}
+#endif /* HAVE_FTW */
+#endif /* HAVE_NFTW */
+
+/*
+ * Find a block device with the right major/minor number.
+ * If we find multiple names, choose the shortest.
+ * If we find a non-standard name, it is probably there
+ * deliberately so prefer it over a standard name.
+ * This applies only to names for MD devices.
+ */
+char *map_dev(int major, int minor, int create)
+{
+	struct devmap *p;
+	char *std = NULL, *nonstd=NULL;
+	int did_check = 0;
+
+	if (major == 0 && minor == 0)
+			return NULL;
+
+ retry:
+	if (!devlist_ready) {
+		char *dev = "/dev";
+		struct stat stb;
+		while(devlist) {
+			struct devmap *d = devlist;
+			devlist = d->next;
+			free(d->name);
+			free(d);
+		}
+		if (lstat(dev, &stb)==0 &&
+		    S_ISLNK(stb.st_mode))
+			dev = "/dev/.";
+		nftw(dev, add_dev, 10, FTW_PHYS);
+		devlist_ready=1;
+		did_check = 1;
+	}
+
+	for (p=devlist; p; p=p->next)
+		if (p->major == major &&
+		    p->minor == minor) {
+			if (is_standard(p->name, NULL)) {
+				if (std == NULL ||
+				    strlen(p->name) < strlen(std))
+					std = p->name;
+			} else {
+				if (nonstd == NULL ||
+				    strlen(p->name) < strlen(nonstd))
+					nonstd = p->name;
+			}
+		}
+	if (!std && !nonstd && !did_check) {
+		devlist_ready = 0;
+		goto retry;
+	}
+	if (create && !std && !nonstd) {
+		static char buf[30];
+		snprintf(buf, sizeof(buf), "%d:%d", major, minor);
+		nonstd = buf;
+	}
+
+	return nonstd ? nonstd : std;
+}
+
+unsigned long calc_csum(void *super, int bytes)
+{
+	unsigned long long newcsum = 0;
+	int i;
+	unsigned int csum;
+	unsigned int *superc = (unsigned int*) super;
+
+	for(i=0; i<bytes/4; i++)
+		newcsum+= superc[i];
+	csum = (newcsum& 0xffffffff) + (newcsum>>32);
+#ifdef __alpha__
+/* The in-kernel checksum calculation is always 16bit on 
+ * the alpha, though it is 32 bit on i386...
+ * I wonder what it is elsewhere... (it uses and API in
+ * a way that it shouldn't).
+ */
+	csum = (csum & 0xffff) + (csum >> 16);
+	csum = (csum & 0xffff) + (csum >> 16);
+#endif
+	return csum;
+}
+
+char *human_size(long long bytes)
+{
+	static char buf[30];
+
+	/* We convert bytes to either centi-M{ega,ibi}bytes or
+	 * centi-G{igi,ibi}bytes, with appropriate rounding,
+	 * and then print 1/100th of those as a decimal.
+	 * We allow upto 2048Megabytes before converting to
+	 * gigabytes, as that shows more precision and isn't
+	 * too large a number.
+	 * Terrabytes are not yet handled.
+	 */
+
+	if (bytes < 5000*1024)
+		buf[0]=0;
+	else if (bytes < 2*1024LL*1024LL*1024LL) {
+		long cMiB = (bytes / ( (1LL<<20) / 200LL ) +1) /2;
+		long cMB  = (bytes / ( 1000000LL / 200LL ) +1) /2;
+		snprintf(buf, sizeof(buf), " (%ld.%02ld MiB %ld.%02ld MB)",
+			cMiB/100 , cMiB % 100,
+			cMB/100, cMB % 100);
+	} else {
+		long cGiB = (bytes / ( (1LL<<30) / 200LL ) +1) /2;
+		long cGB  = (bytes / (1000000000LL/200LL ) +1) /2;
+		snprintf(buf, sizeof(buf), " (%ld.%02ld GiB %ld.%02ld GB)",
+			cGiB/100 , cGiB % 100,
+			cGB/100, cGB % 100);
+	}
+	return buf;
+}
+
+char *human_size_brief(long long bytes)
+{
+	static char buf[30];
+	
+
+	if (bytes < 5000*1024)
+		snprintf(buf, sizeof(buf), "%ld.%02ldKiB",
+			(long)(bytes>>10), (long)(((bytes&1023)*100+512)/1024)
+			);
+	else if (bytes < 2*1024LL*1024LL*1024LL)
+		snprintf(buf, sizeof(buf), "%ld.%02ldMiB",
+			(long)(bytes>>20),
+			(long)((bytes&0xfffff)+0x100000/200)/(0x100000/100)
+			);
+	else
+		snprintf(buf, sizeof(buf), "%ld.%02ldGiB",
+			(long)(bytes>>30),
+			(long)(((bytes>>10)&0xfffff)+0x100000/200)/(0x100000/100)
+			);
+	return buf;
+}
+
+int get_mdp_major(void)
+{
+static int mdp_major = -1;
+	FILE *fl;
+	char *w;
+	int have_block = 0;
+	int have_devices = 0;
+	int last_num = -1;
+
+	if (mdp_major != -1)
+		return mdp_major;
+	fl = fopen("/proc/devices", "r");
+	if (!fl)
+		return -1;
+	while ((w = conf_word(fl, 1))) {
+		if (have_block && strcmp(w, "devices:")==0)
+			have_devices = 1;
+		have_block =  (strcmp(w, "Block")==0);
+		if (isdigit(w[0]))
+			last_num = atoi(w);
+		if (have_devices && strcmp(w, "mdp")==0)
+			mdp_major = last_num;
+		free(w);
+	}
+	fclose(fl);
+	return mdp_major;
+}
+
+int dev_open(char *dev, int flags)
+{
+	/* like 'open', but if 'dev' matches %d:%d, create a temp
+	 * block device and open that
+	 */
+	char *e;
+	int fd = -1;
+	char devname[32];
+	int major;
+	int minor;
+
+	if (!dev) return -1;
+
+	major = strtoul(dev, &e, 0);
+	if (e > dev && *e == ':' && e[1] &&
+	    (minor = strtoul(e+1, &e, 0)) >= 0 &&
+	    *e == 0) {
+		snprintf(devname, sizeof(devname), "/dev/.tmp.md.%d:%d", major, minor);
+		if (mknod(devname, S_IFBLK|0600, makedev(major, minor))==0) {
+			fd = open(devname, flags);
+			unlink(devname);
+		}
+	} else
+		fd = open(dev, flags);
+	return fd;
+}
+
+struct superswitch *superlist[] = { &super0, &super1, NULL };
+
+struct supertype *super_by_version(int vers, int minor)
+{
+	struct supertype *st = malloc(sizeof(*st));
+	if (!st) return st;
+	if (vers == 0) {
+		st->ss = &super0;
+		st->max_devs = MD_SB_DISKS;
+	}
+
+	if (vers == 1) {
+		st->ss = &super1;
+		st->max_devs = 384;
+	}
+	st->minor_version = minor;
+	return st;
+}
+
+struct supertype *guess_super(int fd)
+{
+	/* try each load_super to find the best match,
+	 * and return the best superswitch
+	 */
+	struct superswitch  *ss;
+	struct supertype *st;
+	unsigned long besttime = 0;
+	int bestsuper = -1;
+	
+	void *sbp = NULL;
+	int i;
+
+	st = malloc(sizeof(*st));
+	memset(st, 0, sizeof(*st));
+	for (i=0 ; superlist[i]; i++) {
+		int rv;
+		ss = superlist[i];
+		st->ss = NULL;
+		rv = ss->load_super(st, fd, &sbp, NULL);
+		if (rv == 0) {
+			struct mdinfo info;
+			ss->getinfo_super(&info, sbp);
+			if (bestsuper == -1 ||
+			    besttime < info.array.ctime) {
+				bestsuper = i;
+				besttime = info.array.ctime;
+			}
+			free(sbp);
+		}
+	}
+	if (bestsuper != -1) {
+		int rv;
+		st->ss = NULL;
+		rv = superlist[bestsuper]->load_super(st, fd, &sbp, NULL);
+		if (rv == 0) {
+			free(sbp);
+			return st;
+		}
+	}
+	free(st);
+	return NULL;
+}
+
+/* Return size of device in bytes */
+int get_dev_size(int fd, char *dname, unsigned long long *sizep)
+{
+	unsigned long long ldsize;
+#ifdef BLKGETSIZE64
+	if (ioctl(fd, BLKGETSIZE64, &ldsize) != 0)
+#endif
+	{
+		unsigned long dsize;
+		if (ioctl(fd, BLKGETSIZE, &dsize) == 0) {
+			ldsize = dsize;
+			ldsize <<= 9;
+		} else {
+			if (dname)
+				fprintf(stderr, Name ": Cannot get size of %s: %s\b",
+					dname, strerror(errno));
+			return 0;
+		}
+	}
+	*sizep = ldsize;
+	return 1;
+}
--- busybox-1.7.4+gentoo/mdadm/Kbuild	2008-03-01 18:44:05.526713152 -0800
+++ busybox-1.7.4+gentoo+mdadm/mdadm/Kbuild	2008-03-11 12:19:18.000000000 -0700
@@ -0,0 +1,9 @@
+# Makefile for busybox
+#
+# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
+#
+# Licensed under the GPL v2, see the file LICENSE in this tarball.
+
+lib-y:=
+MDADM-y:= config.o util.o dlink.o sha1.o super0.o super1.o mdexamine.o mdassemble.o
+lib-$(CONFIG_MDADM)	+= mdadm.o $(MDADM-y)