Add busybox patches ported from 1.7.4 to 1.18.1
authorDenis Kaganovich <mahatma@bspu.unibel.by>
Thu, 13 Jan 2011 16:51:29 +0000 (17:51 +0100)
committerSebastian Pipping <sebastian@pipping.org>
Thu, 13 Jan 2011 16:51:29 +0000 (17:51 +0100)
patches/busybox/1.18.1/1.18.1-mdadm.diff [new file with mode: 0644]
patches/busybox/1.18.1/1.18.1-mdstart.diff [new file with mode: 0644]
patches/busybox/1.18.1/1.18.1-openvt.diff [new file with mode: 0644]
patches/busybox/1.18.1/busybox-1.7.4-signal-hack.patch [new file with mode: 0644]

diff --git a/patches/busybox/1.18.1/1.18.1-mdadm.diff b/patches/busybox/1.18.1/1.18.1-mdadm.diff
new file mode 100644 (file)
index 0000000..4b3a51d
--- /dev/null
@@ -0,0 +1,5876 @@
+Based on:
+
+> 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>
+
+--- a/Config.in        2010-12-21 06:31:04.000000000 +0200
++++ mdadm/Config.in    2011-01-12 21:33:01.000000000 +0200
+@@ -749,6 +749,7 @@ source findutils/Config.in
+ source init/Config.in
+ source loginutils/Config.in
+ source e2fsprogs/Config.in
++source mdadm/Config.in
+ source modutils/Config.in
+ source util-linux/Config.in
+ source miscutils/Config.in
+--- a/include/applets.src.h    2010-12-21 06:31:04.000000000 +0200
++++ mdadm/include/applets.src.h        2011-01-12 21:33:01.000000000 +0200
+@@ -206,6 +206,7 @@ IF_KILLALL5(APPLET_ODDNAME(killall5, kil
+ IF_KLOGD(APPLET(klogd, _BB_DIR_SBIN, _BB_SUID_DROP))
+ IF_LAST(APPLET(last, _BB_DIR_USR_BIN, _BB_SUID_DROP))
+ IF_LENGTH(APPLET_NOFORK(length, length, _BB_DIR_USR_BIN, _BB_SUID_DROP, length))
++IF_MDADM(APPLET(mdadm, _BB_DIR_SBIN, _BB_SUID_DROP))
+ IF_LESS(APPLET(less, _BB_DIR_USR_BIN, _BB_SUID_DROP))
+ IF_SETARCH(APPLET_ODDNAME(linux32, setarch, _BB_DIR_BIN, _BB_SUID_DROP, linux32))
+ IF_SETARCH(APPLET_ODDNAME(linux64, setarch, _BB_DIR_BIN, _BB_SUID_DROP, linux64))
+--- a/include/usage.src.h      2010-12-21 06:29:45.000000000 +0200
++++ mdadm/include/usage.src.h  2011-01-12 21:33:01.000000000 +0200
+@@ -2404,6 +2404,11 @@ INSERT
+      "\n      -w      Warn about improperly formatted checksum lines" \
+       )
++#define mdadm_trivial_usage \
++      ""
++#define mdadm_full_usage \
++      "Assemble or Examine the mdadm arrays."
++
+ #define mdev_trivial_usage \
+        "[-s]"
+ #define mdev_full_usage "\n\n" \
+--- a/Makefile 2010-12-21 06:31:43.000000000 +0200
++++ mdadm/Makefile     2011-01-12 21:33:01.000000000 +0200
+@@ -478,6 +478,7 @@ libs-y             := \
+               loginutils/ \
+               mailutils/ \
+               miscutils/ \
++              mdadm/ \
+               modutils/ \
+               networking/ \
+               networking/libiproute/ \
+--- a/mdadm/bitmap.h   1970-01-01 03:00:00.000000000 +0300
++++ mdadm/mdadm/bitmap.h       2011-01-12 21:33:01.000000000 +0200
+@@ -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 -pruN a/mdadm/config.c mdadm/mdadm/config.c
+--- a/mdadm/config.c   1970-01-01 03:00:00.000000000 +0300
++++ mdadm/mdadm/config.c       2011-01-12 21:33:01.000000000 +0200
+@@ -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;
++}
+--- a/mdadm/Config.in  1970-01-01 03:00:00.000000000 +0300
++++ mdadm/mdadm/Config.in      2011-01-12 21:33:01.000000000 +0200
+@@ -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
++
+--- a/mdadm/dlink.c    1970-01-01 03:00:00.000000000 +0300
++++ mdadm/mdadm/dlink.c        2011-01-12 21:33:01.000000000 +0200
+@@ -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));
++}
+--- a/mdadm/dlink.h    1970-01-01 03:00:00.000000000 +0300
++++ mdadm/mdadm/dlink.h        2011-01-12 21:33:01.000000000 +0200
+@@ -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*);
+--- a/mdadm/Kbuild     1970-01-01 03:00:00.000000000 +0300
++++ mdadm/mdadm/Kbuild 2011-01-12 21:33:01.000000000 +0200
+@@ -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)
+--- a/mdadm/md5.h      1970-01-01 03:00:00.000000000 +0300
++++ mdadm/mdadm/md5.h  2011-01-12 21:33:01.000000000 +0200
+@@ -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 */
+--- a/mdadm/mdadm.c    1970-01-01 03:00:00.000000000 +0300
++++ mdadm/mdadm/mdadm.c        2011-01-12 21:33:01.000000000 +0200
+@@ -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;
++}
+--- a/mdadm/mdadm.h    1970-01-01 03:00:00.000000000 +0300
++++ mdadm/mdadm/mdadm.h        2011-01-12 21:33:01.000000000 +0200
+@@ -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
+--- a/mdadm/mdassemble.c       1970-01-01 03:00:00.000000000 +0300
++++ mdadm/mdadm/mdassemble.c   2011-01-12 21:33:01.000000000 +0200
+@@ -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;
++}
++
+--- a/mdadm/mdexamine.c        1970-01-01 03:00:00.000000000 +0300
++++ mdadm/mdadm/mdexamine.c    2011-01-12 21:33:01.000000000 +0200
+@@ -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);
++}
++
+--- a/mdadm/md_p.h     1970-01-01 03:00:00.000000000 +0300
++++ mdadm/mdadm/md_p.h 2011-01-12 21:33:01.000000000 +0200
+@@ -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 
++
+--- a/mdadm/md_u.h     1970-01-01 03:00:00.000000000 +0300
++++ mdadm/mdadm/md_u.h 2011-01-12 21:33:01.000000000 +0200
+@@ -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 
++
+--- a/mdadm/sha1.c     1970-01-01 03:00:00.000000000 +0300
++++ mdadm/mdadm/sha1.c 2011-01-12 21:33:01.000000000 +0200
+@@ -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;
++    }
++}
+--- a/mdadm/sha1.h     1970-01-01 03:00:00.000000000 +0300
++++ mdadm/mdadm/sha1.h 2011-01-12 21:33:01.000000000 +0200
+@@ -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
+--- a/mdadm/super0.c   1970-01-01 03:00:00.000000000 +0300
++++ mdadm/mdadm/super0.c       2011-01-12 21:33:01.000000000 +0200
+@@ -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,
++};
+--- a/mdadm/super1.c   1970-01-01 03:00:00.000000000 +0300
++++ mdadm/mdadm/super1.c       2011-01-12 21:33:01.000000000 +0200
+@@ -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
++};
+--- a/mdadm/util.c     1970-01-01 03:00:00.000000000 +0300
++++ mdadm/mdadm/util.c 2011-01-12 21:33:01.000000000 +0200
+@@ -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;
++}
diff --git a/patches/busybox/1.18.1/1.18.1-mdstart.diff b/patches/busybox/1.18.1/1.18.1-mdstart.diff
new file mode 100644 (file)
index 0000000..f4abaa5
--- /dev/null
@@ -0,0 +1,113 @@
+Based on:
+
+> Forward-port the old mdstart tool from the Gentoo Busybox-1.1.3.
+> Only fires the RAID_AUTORUN ioctl on existing /dev/md nodes.
+
+> Signed-off-by: Robin H. Johnson <robbat2@gentoo.org>
+
+diff -pruN a/include/usage.src.h mdstart/include/usage.src.h
+--- a/include/usage.src.h      2010-12-21 06:29:45.000000000 +0200
++++ mdstart/include/usage.src.h        2011-01-12 21:29:47.000000000 +0200
+@@ -847,6 +847,11 @@ INSERT
+        "$ dirname /tmp/foo/\n" \
+        "/tmp\n"
++#define mdstart_trivial_usage \
++      "{[PARTITION] MD-NODE}..."
++#define mdstart_full_usage \
++      Run the RAID_AUTORUN ioctl on the given MD number"
++
+ #define dmesg_trivial_usage \
+        "[-c] [-n LEVEL] [-s SIZE]"
+ #define dmesg_full_usage "\n\n" \
+diff -pruN a/util-linux/Config.src mdstart/util-linux/Config.src
+--- a/util-linux/Config.src    2010-12-20 02:41:27.000000000 +0200
++++ mdstart/util-linux/Config.src      2011-01-12 21:30:09.000000000 +0200
+@@ -456,6 +456,13 @@ config FEATURE_MDEV_LOAD_FIRMWARE
+         /lib/firmware/ and if it exists, send it to the kernel for
+         loading into the hardware.
++config MDSTART
++      bool "mdstart"
++      default n
++      help
++        Allows you to autostart /dev/md devices if using an initramfs to
++        boot.
++
+ config MKSWAP
+       bool "mkswap"
+       default y
+diff -pruN a/util-linux/Kbuild.src mdstart/util-linux/Kbuild.src
+--- a/util-linux/Kbuild.src    2010-12-20 02:41:27.000000000 +0200
++++ mdstart/util-linux/Kbuild.src      2011-01-12 21:30:09.000000000 +0200
+@@ -24,6 +24,7 @@ lib-$(CONFIG_HWCLOCK)           += hwclo
+ lib-$(CONFIG_IPCRM)             += ipcrm.o
+ lib-$(CONFIG_IPCS)              += ipcs.o
+ lib-$(CONFIG_LOSETUP)           += losetup.o
++lib-$(CONFIG_MDSTART)          += mdStart.o
+ lib-$(CONFIG_LSPCI)             += lspci.o
+ lib-$(CONFIG_LSUSB)             += lsusb.o
+ lib-$(CONFIG_MDEV)              += mdev.o
+diff -pruN a/util-linux/mdStart.c mdstart/util-linux/mdStart.c
+--- a/util-linux/mdStart.c     1970-01-01 03:00:00.000000000 +0300
++++ mdstart/util-linux/mdStart.c       2011-01-12 21:30:09.000000000 +0200
+@@ -0,0 +1,59 @@
++/*
++ * Linux 2.6(+) RAID Autostarter
++ *
++ * Copyright (C) 2005 by Tim Yamin <plasmaroo@gentoo.org> <plasm@roo.me.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <fcntl.h>
++#include <sys/ioctl.h>
++#include <linux/major.h>
++#include <linux/raid/md_u.h>
++
++extern int
++mdstart_main(int argc, char *argv[])
++{
++      int i, fd, part = 0, retval = 0;
++
++      if(argc < 2)
++      {
++              bb_show_usage();
++      }
++
++      for(i = 1; i < argc; i++)
++      {
++              if(sscanf(argv[i], "%d", &part) == 1)
++                      continue;
++
++              fd = open(argv[i], 0, 0);
++              if (fd >= 0)
++              {
++                      ioctl(fd, RAID_AUTORUN, part);
++                      close(fd);
++              } else
++              {
++                      printf("Error: Failed to open %s!\n", argv[i]);
++                      retval=1;
++              }
++
++              part = 0;
++      }
++
++      return retval;
++}
diff --git a/patches/busybox/1.18.1/1.18.1-openvt.diff b/patches/busybox/1.18.1/1.18.1-openvt.diff
new file mode 100644 (file)
index 0000000..658bee9
--- /dev/null
@@ -0,0 +1,21 @@
+Based on:
+
+> Allow a slightly wider range of valid vt numbers. Forward-ported from Gentoo
+> Busybox 1.1.3.
+
+> The previous spin of this patch on 1.1.3 had a 'wait(NULL);' right before
+> return EXIT_SUCCESS. I don't think it's needed anymore, so I left it out.
+
+> Signed-off-by: Robin H. Johnson <robbat2@gentoo.org>
+
+--- a/console-tools/openvt.c   2010-11-22 22:24:58.000000000 +0200
++++ b/console-tools/openvt.c   2010-11-29 15:32:18.000000000 +0200
+@@ -124,7 +124,7 @@ int openvt_main(int argc UNUSED_PARAM, c
+       if (flags & OPT_c) {
+               /* Check for illegal vt number: < 1 or > 63 */
+-              vtno = xatou_range(str_c, 1, 63);
++              vtno = xatou_range(str_c, 0, 63);
+       } else {
+               vtno = find_free_vtno();
+       }
diff --git a/patches/busybox/1.18.1/busybox-1.7.4-signal-hack.patch b/patches/busybox/1.18.1/busybox-1.7.4-signal-hack.patch
new file mode 100644 (file)
index 0000000..ba11830
--- /dev/null
@@ -0,0 +1,28 @@
+workaround while we get it fixed upstream
+
+http://bugs.gentoo.org/201114
+
+--- libbb/u_signal_names.c
++++ libbb/u_signal_names.c
+@@ -66,7 +66,7 @@
+ #ifdef SIGTERM
+       [SIGTERM  ] = "TERM",
+ #endif
+-#ifdef SIGSTKFLT
++#if defined(SIGSTKFLT) && SIGSTKFLT < 32
+       [SIGSTKFLT] = "STKFLT",
+ #endif
+ #ifdef SIGCHLD
+@@ -90,10 +90,10 @
+ #ifdef SIGURG
+       [SIGURG   ] = "URG",
+ #endif
+-#ifdef SIGXCPU
++#if defined(SIGXCPU) && SIGXCPU < 32
+       [SIGXCPU  ] = "XCPU",
+ #endif
+-#ifdef SIGXFSZ
++#if defined(SIGXFSZ) && SIGXFSZ < 32
+       [SIGXFSZ  ] = "XFSZ",
+ #endif
+ #ifdef SIGVTALRM