From e86db7cf2c6400ecb48d01aca7320905d2998c82 Mon Sep 17 00:00:00 2001 From: Andrew Gaffney Date: Tue, 11 Mar 2008 18:07:17 +0000 Subject: Add apply_patches() function to automagically apply patches for a given util Add updated busybox patches for 1.7.4 from robbat2 Change BUSYBOX_VER to 1.7.4 git-svn-id: svn+ssh://svn.gentoo.org/var/svnroot/genkernel/trunk@616 67a159dc-881f-0410-a524-ba9dfbe2cb84 --- patches/busybox/1.7.4/1.7.4-ash-timeout.diff | 123 + patches/busybox/1.7.4/1.7.4-mdadm.diff | 5932 ++++++++++++++++++++++++++ patches/busybox/1.7.4/1.7.4-mdstart.diff | 120 + patches/busybox/1.7.4/1.7.4-openvt.diff | 20 + 4 files changed, 6195 insertions(+) create mode 100644 patches/busybox/1.7.4/1.7.4-ash-timeout.diff create mode 100644 patches/busybox/1.7.4/1.7.4-mdadm.diff create mode 100644 patches/busybox/1.7.4/1.7.4-mdstart.diff create mode 100644 patches/busybox/1.7.4/1.7.4-openvt.diff (limited to 'patches') diff --git a/patches/busybox/1.7.4/1.7.4-ash-timeout.diff b/patches/busybox/1.7.4/1.7.4-ash-timeout.diff new file mode 100644 index 0000000..25d5338 --- /dev/null +++ b/patches/busybox/1.7.4/1.7.4-ash-timeout.diff @@ -0,0 +1,123 @@ +'read -t' support, forward-ported from Gentoo Busybox 1.1.3. +Used during the LiveCD boot when prompting for a keymap. + +Signed-off-by: Robin H. Johnson + +diff -Nuar --exclude '*.orig' busybox-1.7.4/shell/ash.c busybox-1.7.4+gentoo/shell/ash.c +--- busybox-1.7.4/shell/ash.c 2007-11-03 16:06:35.000000000 -0700 ++++ busybox-1.7.4+gentoo/shell/ash.c 2008-03-11 10:21:28.000000000 -0700 +@@ -11485,11 +11485,13 @@ + int startword; + int status; + int i; ++#if ENABLE_ASH_READ_NCHARS || ENABLE_ASH_READ_TIMEOUT ++ struct termios tty, old_tty; ++#endif + #if ENABLE_ASH_READ_NCHARS + int nch_flag = 0; + int nchars = 0; + int silent = 0; +- struct termios tty, old_tty; + #endif + #if ENABLE_ASH_READ_TIMEOUT + fd_set set; +@@ -11566,44 +11568,74 @@ + ifs = bltinlookup("IFS"); + if (ifs == NULL) + ifs = defifs; +-#if ENABLE_ASH_READ_NCHARS ++#if ENABLE_ASH_READ_NCHARS || ENABLE_ASH_READ_TIMEOUT ++#if ENABLE_ASH_READ_NCHARS && ENABLE_ASH_READ_TIMEOUT ++ if (nch_flag || silent || ts.tv_sec || ts.tv_usec) { ++#elif ENABLE_ASH_READ_TIMEOUT ++ if (ts.tv_sec || ts.tv_usec) { ++#elif ENABLE_ASH_READ_NCHARS + if (nch_flag || silent) { ++#endif + tcgetattr(0, &tty); + old_tty = tty; +- if (nch_flag) { ++#if ENABLE_ASH_READ_NCHARS && ENABLE_ASH_READ_TIMEOUT ++ if (nch_flag || ts.tv_sec || ts.tv_usec) ++#elif ENABLE_ASH_READ_TIMEOUT ++ if (ts.tv_sec || ts.tv_usec) ++#elif ENABLE_ASH_READ_NCHARS ++ if (nch_flag) ++#endif + tty.c_lflag &= ~ICANON; +- tty.c_cc[VMIN] = nchars; +- } +- if (silent) { +- tty.c_lflag &= ~(ECHO|ECHOK|ECHONL); + +- } ++ ++#if ENABLE_ASH_READ_NCHARS ++ if (silent) ++ tty.c_lflag &= ~(ECHO|ECHOK|ECHONL); ++#endif + tcsetattr(0, TCSANOW, &tty); + } + #endif ++ i = 1; ++ STARTSTACKSTR(p); + #if ENABLE_ASH_READ_TIMEOUT + if (ts.tv_sec || ts.tv_usec) { + FD_ZERO(&set); + FD_SET(0, &set); + + i = select(FD_SETSIZE, &set, NULL, NULL, &ts); +- if (!i) { ++ if (i == 1) ++ { ++ read(0, &c, 1); ++ if(c == '\n' || c == 4) /* Handle newlines and EOF */ ++ i = 0; /* Don't read further... */ ++ else ++ STPUTC(c, p); /* Ok, keep reading... */ ++ } + #if ENABLE_ASH_READ_NCHARS +- if (nch_flag) +- tcsetattr(0, TCSANOW, &old_tty); ++ if (!silent && !nch_flag) + #endif +- return 1; ++ tcsetattr(0, TCSANOW, &old_tty); ++ ++#if ENABLE_ASH_READ_NCHARS ++ if(i == 0) ++ { ++ nchars = 0; ++ nch_flag = 1; ++ } else ++ { ++ if (nch_flag) ++ nchars--; + } ++#endif + } + #endif + status = 0; + startword = 1; + backslash = 0; +- STARTSTACKSTR(p); + #if ENABLE_ASH_READ_NCHARS + while (!nch_flag || nchars--) + #else +- for (;;) ++ for (;i > 0;) + #endif + { + if (read(0, &c, 1) != 1) { +@@ -11640,8 +11672,10 @@ + } + } + #if ENABLE_ASH_READ_NCHARS +- if (nch_flag || silent) ++ if (silent || nch_flag) + tcsetattr(0, TCSANOW, &old_tty); ++ if (!silent && nch_flag) ++ printf("\n"); + #endif + + STACKSTRNUL(p); diff --git a/patches/busybox/1.7.4/1.7.4-mdadm.diff b/patches/busybox/1.7.4/1.7.4-mdadm.diff new file mode 100644 index 0000000..6e1932d --- /dev/null +++ b/patches/busybox/1.7.4/1.7.4-mdadm.diff @@ -0,0 +1,5932 @@ +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 + +diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/Config.in busybox-1.7.4+gentoo+mdadm/Config.in +--- busybox-1.7.4+gentoo/Config.in 2007-09-03 04:48:58.000000000 -0700 ++++ busybox-1.7.4+gentoo+mdadm/Config.in 2008-03-11 10:31:00.000000000 -0700 +@@ -499,2 +499,3 @@ + source e2fsprogs/Config.in ++source mdadm/Config.in + source modutils/Config.in +diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/include/applets.h busybox-1.7.4+gentoo+mdadm/include/applets.h +--- busybox-1.7.4+gentoo/include/applets.h 2008-03-11 10:25:43.000000000 -0700 ++++ busybox-1.7.4+gentoo+mdadm/include/applets.h 2008-03-11 10:32:22.000000000 -0700 +@@ -223,2 +223,3 @@ + USE_MD5SUM(APPLET_ODDNAME(md5sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_NEVER, md5sum)) ++USE_MDADM(APPLET(mdadm, mdadm_main, _BB_DIR_SBIN, _BB_SUID_NEVER)) + USE_MDEV(APPLET(mdev, _BB_DIR_SBIN, _BB_SUID_NEVER)) +diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/include/usage.h busybox-1.7.4+gentoo+mdadm/include/usage.h +--- busybox-1.7.4+gentoo/include/usage.h 2008-03-11 10:19:04.000000000 -0700 ++++ busybox-1.7.4+gentoo+mdadm/include/usage.h 2008-03-11 10:31:00.000000000 -0700 +@@ -2048,2 +2048,7 @@ + ++#define mdadm_trivial_usage \ ++ "" ++#define mdadm_full_usage \ ++ "Assemble or Examine the mdadm arrays." ++ + #define mdev_trivial_usage \ +diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/Makefile busybox-1.7.4+gentoo+mdadm/Makefile +--- busybox-1.7.4+gentoo/Makefile 2007-11-23 20:34:41.000000000 -0800 ++++ busybox-1.7.4+gentoo+mdadm/Makefile 2008-03-11 10:31:49.000000000 -0700 +@@ -442,6 +442,7 @@ + libpwdgrp/ \ + loginutils/ \ + miscutils/ \ ++ mdadm/ \ + modutils/ \ + networking/ \ + networking/libiproute/ \ +diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/mdadm/bitmap.h busybox-1.7.4+gentoo+mdadm/mdadm/bitmap.h +--- busybox-1.7.4+gentoo/mdadm/bitmap.h 1969-12-31 16:00:00.000000000 -0800 ++++ busybox-1.7.4+gentoo+mdadm/mdadm/bitmap.h 2008-03-11 10:31:00.000000000 -0700 +@@ -0,0 +1,287 @@ ++/* ++ * bitmap.h: Copyright (C) Peter T. Breuer (ptb@ot.uc3m.es) 2003 ++ * ++ * additions: Copyright (C) 2003-2004, Paul Clements, SteelEye Technology, Inc. ++ */ ++#ifndef BITMAP_H ++#define BITMAP_H 1 ++ ++#define BITMAP_MAJOR_LO 3 ++/* version 4 insists the bitmap is in little-endian order ++ * with version 3, it is host-endian which is non-portable ++ */ ++#define BITMAP_MAJOR_HI 4 ++#define BITMAP_MAJOR_HOSTENDIAN 3 ++ ++#define BITMAP_MINOR 39 ++ ++/* ++ * in-memory bitmap: ++ * ++ * Use 16 bit block counters to track pending writes to each "chunk". ++ * The 2 high order bits are special-purpose, the first is a flag indicating ++ * whether a resync is needed. The second is a flag indicating whether a ++ * resync is active. ++ * This means that the counter is actually 14 bits: ++ * ++ * +--------+--------+------------------------------------------------+ ++ * | resync | resync | counter | ++ * | needed | active | | ++ * | (0-1) | (0-1) | (0-16383) | ++ * +--------+--------+------------------------------------------------+ ++ * ++ * The "resync needed" bit is set when: ++ * a '1' bit is read from storage at startup. ++ * a write request fails on some drives ++ * a resync is aborted on a chunk with 'resync active' set ++ * It is cleared (and resync-active set) when a resync starts across all drives ++ * of the chunk. ++ * ++ * ++ * The "resync active" bit is set when: ++ * a resync is started on all drives, and resync_needed is set. ++ * resync_needed will be cleared (as long as resync_active wasn't already set). ++ * It is cleared when a resync completes. ++ * ++ * The counter counts pending write requests, plus the on-disk bit. ++ * When the counter is '1' and the resync bits are clear, the on-disk ++ * bit can be cleared aswell, thus setting the counter to 0. ++ * When we set a bit, or in the counter (to start a write), if the fields is ++ * 0, we first set the disk bit and set the counter to 1. ++ * ++ * If the counter is 0, the on-disk bit is clear and the stipe is clean ++ * Anything that dirties the stipe pushes the counter to 2 (at least) ++ * and sets the on-disk bit (lazily). ++ * If a periodic sweep find the counter at 2, it is decremented to 1. ++ * If the sweep find the counter at 1, the on-disk bit is cleared and the ++ * counter goes to zero. ++ * ++ * Also, we'll hijack the "map" pointer itself and use it as two 16 bit block ++ * counters as a fallback when "page" memory cannot be allocated: ++ * ++ * Normal case (page memory allocated): ++ * ++ * page pointer (32-bit) ++ * ++ * [ ] ------+ ++ * | ++ * +-------> [ ][ ]..[ ] (4096 byte page == 2048 counters) ++ * c1 c2 c2048 ++ * ++ * Hijacked case (page memory allocation failed): ++ * ++ * hijacked page pointer (32-bit) ++ * ++ * [ ][ ] (no page memory allocated) ++ * counter #1 (16-bit) counter #2 (16-bit) ++ * ++ */ ++ ++#ifdef __KERNEL__ ++ ++#define PAGE_BITS (PAGE_SIZE << 3) ++#define PAGE_BIT_SHIFT (PAGE_SHIFT + 3) ++ ++typedef __u16 bitmap_counter_t; ++#define COUNTER_BITS 16 ++#define COUNTER_BIT_SHIFT 4 ++#define COUNTER_BYTE_RATIO (COUNTER_BITS / 8) ++#define COUNTER_BYTE_SHIFT (COUNTER_BIT_SHIFT - 3) ++ ++#define NEEDED_MASK ((bitmap_counter_t) (1 << (COUNTER_BITS - 1))) ++#define RESYNC_MASK ((bitmap_counter_t) (1 << (COUNTER_BITS - 2))) ++#define COUNTER_MAX ((bitmap_counter_t) RESYNC_MASK - 1) ++#define NEEDED(x) (((bitmap_counter_t) x) & NEEDED_MASK) ++#define RESYNC(x) (((bitmap_counter_t) x) & RESYNC_MASK) ++#define COUNTER(x) (((bitmap_counter_t) x) & COUNTER_MAX) ++ ++/* how many counters per page? */ ++#define PAGE_COUNTER_RATIO (PAGE_BITS / COUNTER_BITS) ++/* same, except a shift value for more efficient bitops */ ++#define PAGE_COUNTER_SHIFT (PAGE_BIT_SHIFT - COUNTER_BIT_SHIFT) ++/* same, except a mask value for more efficient bitops */ ++#define PAGE_COUNTER_MASK (PAGE_COUNTER_RATIO - 1) ++ ++#define BITMAP_BLOCK_SIZE 512 ++#define BITMAP_BLOCK_SHIFT 9 ++ ++/* how many blocks per chunk? (this is variable) */ ++#define CHUNK_BLOCK_RATIO(bitmap) ((bitmap)->chunksize >> BITMAP_BLOCK_SHIFT) ++#define CHUNK_BLOCK_SHIFT(bitmap) ((bitmap)->chunkshift - BITMAP_BLOCK_SHIFT) ++#define CHUNK_BLOCK_MASK(bitmap) (CHUNK_BLOCK_RATIO(bitmap) - 1) ++ ++/* when hijacked, the counters and bits represent even larger "chunks" */ ++/* there will be 1024 chunks represented by each counter in the page pointers */ ++#define PAGEPTR_BLOCK_RATIO(bitmap) \ ++ (CHUNK_BLOCK_RATIO(bitmap) << PAGE_COUNTER_SHIFT >> 1) ++#define PAGEPTR_BLOCK_SHIFT(bitmap) \ ++ (CHUNK_BLOCK_SHIFT(bitmap) + PAGE_COUNTER_SHIFT - 1) ++#define PAGEPTR_BLOCK_MASK(bitmap) (PAGEPTR_BLOCK_RATIO(bitmap) - 1) ++ ++/* ++ * on-disk bitmap: ++ * ++ * Use one bit per "chunk" (block set). We do the disk I/O on the bitmap ++ * file a page at a time. There's a superblock at the start of the file. ++ */ ++ ++/* map chunks (bits) to file pages - offset by the size of the superblock */ ++#define CHUNK_BIT_OFFSET(chunk) ((chunk) + (sizeof(bitmap_super_t) << 3)) ++ ++#endif ++ ++/* ++ * bitmap structures: ++ */ ++ ++#define BITMAP_MAGIC 0x6d746962 ++ ++/* use these for bitmap->flags and bitmap->sb->state bit-fields */ ++enum bitmap_state { ++ BITMAP_ACTIVE = 0x001, /* the bitmap is in use */ ++ BITMAP_STALE = 0x002 /* the bitmap file is out of date or had -EIO */ ++}; ++ ++/* the superblock at the front of the bitmap file -- little endian */ ++typedef struct bitmap_super_s { ++ __u32 magic; /* 0 BITMAP_MAGIC */ ++ __u32 version; /* 4 the bitmap major for now, could change... */ ++ __u8 uuid[16]; /* 8 128 bit uuid - must match md device uuid */ ++ __u64 events; /* 24 event counter for the bitmap (1)*/ ++ __u64 events_cleared;/*32 event counter when last bit cleared (2) */ ++ __u64 sync_size; /* 40 the size of the md device's sync range(3) */ ++ __u32 state; /* 48 bitmap state information */ ++ __u32 chunksize; /* 52 the bitmap chunk size in bytes */ ++ __u32 daemon_sleep; /* 56 seconds between disk flushes */ ++ __u32 write_behind; /* 60 number of outstanding write-behind writes */ ++ ++ __u8 pad[256 - 64]; /* set to zero */ ++} bitmap_super_t; ++ ++/* notes: ++ * (1) This event counter is updated before the eventcounter in the md superblock ++ * When a bitmap is loaded, it is only accepted if this event counter is equal ++ * to, or one greater than, the event counter in the superblock. ++ * (2) This event counter is updated when the other one is *if*and*only*if* the ++ * array is not degraded. As bits are not cleared when the array is degraded, ++ * this represents the last time that any bits were cleared. ++ * If a device is being added that has an event count with this value or ++ * higher, it is accepted as conforming to the bitmap. ++ * (3)This is the number of sectors represented by the bitmap, and is the range that ++ * resync happens across. For raid1 and raid5/6 it is the size of individual ++ * devices. For raid10 it is the size of the array. ++ */ ++ ++#ifdef __KERNEL__ ++ ++/* the in-memory bitmap is represented by bitmap_pages */ ++struct bitmap_page { ++ /* ++ * map points to the actual memory page ++ */ ++ char *map; ++ /* ++ * in emergencies (when map cannot be alloced), hijack the map ++ * pointer and use it as two counters itself ++ */ ++ unsigned int hijacked; ++ /* ++ * count of dirty bits on the page ++ */ ++ int count; ++}; ++ ++/* keep track of bitmap file pages that have pending writes on them */ ++struct page_list { ++ struct list_head list; ++ struct page *page; ++}; ++ ++/* the main bitmap structure - one per mddev */ ++struct bitmap { ++ struct bitmap_page *bp; ++ unsigned long pages; /* total number of pages in the bitmap */ ++ unsigned long missing_pages; /* number of pages not yet allocated */ ++ ++ mddev_t *mddev; /* the md device that the bitmap is for */ ++ ++ int counter_bits; /* how many bits per block counter */ ++ ++ /* bitmap chunksize -- how much data does each bit represent? */ ++ unsigned long chunksize; ++ unsigned long chunkshift; /* chunksize = 2^chunkshift (for bitops) */ ++ unsigned long chunks; /* total number of data chunks for the array */ ++ ++ /* We hold a count on the chunk currently being synced, and drop ++ * it when the last block is started. If the resync is aborted ++ * midway, we need to be able to drop that count, so we remember ++ * the counted chunk.. ++ */ ++ unsigned long syncchunk; ++ ++ __u64 events_cleared; ++ ++ /* bitmap spinlock */ ++ spinlock_t lock; ++ ++ struct file *file; /* backing disk file */ ++ struct page *sb_page; /* cached copy of the bitmap file superblock */ ++ struct page **filemap; /* list of cache pages for the file */ ++ unsigned long *filemap_attr; /* attributes associated w/ filemap pages */ ++ unsigned long file_pages; /* number of pages in the file */ ++ ++ unsigned long flags; ++ ++ /* ++ * the bitmap daemon - periodically wakes up and sweeps the bitmap ++ * file, cleaning up bits and flushing out pages to disk as necessary ++ */ ++ mdk_thread_t *daemon; ++ unsigned long daemon_sleep; /* how many seconds between updates? */ ++ ++ /* ++ * bitmap write daemon - this daemon performs writes to the bitmap file ++ * this thread is only needed because of a limitation in ext3 (jbd) ++ * that does not allow a task to have two journal transactions ongoing ++ * simultaneously (even if the transactions are for two different ++ * filesystems) -- in the case of bitmap, that would be the filesystem ++ * that the bitmap file resides on and the filesystem that is mounted ++ * on the md device -- see current->journal_info in jbd/transaction.c ++ */ ++ mdk_thread_t *write_daemon; ++ mdk_thread_t *writeback_daemon; ++ spinlock_t write_lock; ++ struct semaphore write_ready; ++ struct semaphore write_done; ++ unsigned long writes_pending; ++ wait_queue_head_t write_wait; ++ struct list_head write_pages; ++ struct list_head complete_pages; ++ mempool_t *write_pool; ++}; ++ ++/* the bitmap API */ ++ ++/* these are used only by md/bitmap */ ++int bitmap_create(mddev_t *mddev); ++void bitmap_destroy(mddev_t *mddev); ++int bitmap_active(struct bitmap *bitmap); ++ ++char *file_path(struct file *file, char *buf, int count); ++void bitmap_print_sb(struct bitmap *bitmap); ++int bitmap_update_sb(struct bitmap *bitmap); ++ ++int bitmap_setallbits(struct bitmap *bitmap); ++ ++/* these are exported */ ++void bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sectors); ++void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long sectors, ++ int success); ++int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks); ++void bitmap_end_sync(struct bitmap *bitmap, sector_t offset, int *blocks, int aborted); ++void bitmap_close_sync(struct bitmap *bitmap); ++ ++int bitmap_unplug(struct bitmap *bitmap); ++#endif ++ ++#endif +diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/mdadm/config.c busybox-1.7.4+gentoo+mdadm/mdadm/config.c +--- busybox-1.7.4+gentoo/mdadm/config.c 1969-12-31 16:00:00.000000000 -0800 ++++ busybox-1.7.4+gentoo+mdadm/mdadm/config.c 2008-03-11 10:31:00.000000000 -0700 +@@ -0,0 +1,824 @@ ++/* ++ * mdadm - manage Linux "md" devices aka RAID arrays. ++ * ++ * Copyright (C) 2001-2006 Neil Brown ++ * ++ * ++ * 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: ++ * 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 ++#include ++#include ++#include ++#include ++#include ++ ++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; idevname = strdup(globbuf.gl_pathv[i]); ++ t->next = dlist; ++ t->used = 0; ++ dlist = t; ++/* printf("one dev is %s\n", t->devname);*/ ++ } ++ globfree(&globbuf); ++ } ++ ++ return dlist; ++} ++ ++int conf_test_dev(char *devname) ++{ ++ struct conf_dev *cd; ++ if (cdevlist == NULL) ++ /* allow anything by default */ ++ return 1; ++ for (cd = cdevlist ; cd ; cd = cd->next) { ++ if (strcasecmp(cd->name, "partitions") == 0) ++ return 1; ++ if (fnmatch(cd->name, devname, FNM_PATHNAME) == 0) ++ return 1; ++ } ++ return 0; ++} ++ ++ ++int match_oneof(char *devices, char *devname) ++{ ++ /* check if one of the comma separated patterns in devices ++ * matches devname ++ */ ++ ++ ++ while (devices && *devices) { ++ char patn[1024]; ++ char *p = devices; ++ devices = strchr(devices, ','); ++ if (!devices) ++ devices = p + strlen(p); ++ if (devices-p < 1024) { ++ strncpy(patn, p, devices-p); ++ patn[devices-p] = 0; ++ if (fnmatch(patn, devname, FNM_PATHNAME)==0) ++ return 1; ++ } ++ if (*devices == ',') ++ devices++; ++ } ++ return 0; ++} +diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/mdadm/Config.in busybox-1.7.4+gentoo+mdadm/mdadm/Config.in +--- busybox-1.7.4+gentoo/mdadm/Config.in 1969-12-31 16:00:00.000000000 -0800 ++++ busybox-1.7.4+gentoo+mdadm/mdadm/Config.in 2008-03-11 10:31:00.000000000 -0700 +@@ -0,0 +1,15 @@ ++# ++# For a description of the syntax of this configuration file, ++# see scripts/kbuild/config-language.txt. ++# ++ ++menu "Linux mdadm Utilities" ++ ++config CONFIG_MDADM ++ bool "mdadm" ++ default n ++ help ++ assemble or examine raid array ++ ++endmenu ++ +diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/mdadm/dlink.c busybox-1.7.4+gentoo+mdadm/mdadm/dlink.c +--- busybox-1.7.4+gentoo/mdadm/dlink.c 1969-12-31 16:00:00.000000000 -0800 ++++ busybox-1.7.4+gentoo+mdadm/mdadm/dlink.c 2008-03-11 10:31:00.000000000 -0700 +@@ -0,0 +1,79 @@ ++ ++/* doubly linked lists */ ++/* This is free software. No strings attached. No copyright claimed */ ++ ++#include ++#include ++#include ++#ifdef __dietlibc__ ++char *strncpy(char *dest, const char *src, size_t n) __THROW; ++#endif ++#include "dlink.h" ++ ++ ++void *dl_head() ++{ ++ void *h; ++ h = dl_alloc(0); ++ dl_next(h) = h; ++ dl_prev(h) = h; ++ return h; ++} ++ ++void dl_free(void *v) ++{ ++ struct __dl_head *vv = v; ++ free(vv-1); ++} ++ ++void dl_init(void *v) ++{ ++ dl_next(v) = v; ++ dl_prev(v) = v; ++} ++ ++void dl_insert(void *head, void *val) ++{ ++ dl_next(val) = dl_next(head); ++ dl_prev(val) = head; ++ dl_next(dl_prev(val)) = val; ++ dl_prev(dl_next(val)) = val; ++} ++ ++void dl_add(void *head, void *val) ++{ ++ dl_prev(val) = dl_prev(head); ++ dl_next(val) = head; ++ dl_next(dl_prev(val)) = val; ++ dl_prev(dl_next(val)) = val; ++} ++ ++void dl_del(void *val) ++{ ++ if (dl_prev(val) == 0 || dl_next(val) == 0) ++ return; ++ dl_prev(dl_next(val)) = dl_prev(val); ++ dl_next(dl_prev(val)) = dl_next(val); ++ dl_prev(val) = dl_next(val) = 0; ++} ++ ++char *dl_strndup(char *s, int l) ++{ ++ char *n; ++ if (s == NULL) ++ return NULL; ++ n = dl_newv(char, l+1); ++ if (n == NULL) ++ return NULL; ++ else ++ { ++ strncpy(n, s, l); ++ n[l] = 0; ++ return n; ++ } ++} ++ ++char *dl_strdup(char *s) ++{ ++ return dl_strndup(s, (int)strlen(s)); ++} +diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/mdadm/dlink.h busybox-1.7.4+gentoo+mdadm/mdadm/dlink.h +--- busybox-1.7.4+gentoo/mdadm/dlink.h 1969-12-31 16:00:00.000000000 -0800 ++++ busybox-1.7.4+gentoo+mdadm/mdadm/dlink.h 2008-03-11 10:31:00.000000000 -0700 +@@ -0,0 +1,25 @@ ++ ++/* doubley linked lists */ ++/* This is free software. No strings attached. No copyright claimed */ ++ ++struct __dl_head ++{ ++ void * dh_prev; ++ void * dh_next; ++}; ++ ++#define dl_alloc(size) ((void*)(((char*)calloc(1,(size)+sizeof(struct __dl_head)))+sizeof(struct __dl_head))) ++#define dl_new(t) ((t*)dl_alloc(sizeof(t))) ++#define dl_newv(t,n) ((t*)dl_alloc(sizeof(t)*n)) ++ ++#define dl_next(p) *(&(((struct __dl_head*)(p))[-1].dh_next)) ++#define dl_prev(p) *(&(((struct __dl_head*)(p))[-1].dh_prev)) ++ ++void *dl_head(void); ++char *dl_strdup(char *); ++char *dl_strndup(char *, int); ++void dl_insert(void*, void*); ++void dl_add(void*, void*); ++void dl_del(void*); ++void dl_free(void*); ++void dl_init(void*); +diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/mdadm/Makefile busybox-1.7.4+gentoo+mdadm/mdadm/Makefile +--- busybox-1.7.4+gentoo/mdadm/Makefile 1969-12-31 16:00:00.000000000 -0800 ++++ busybox-1.7.4+gentoo+mdadm/mdadm/Makefile 2008-03-11 10:31:00.000000000 -0700 +@@ -0,0 +1,23 @@ ++# Makefile for busybox ++# ++# Copyright (C) 1999-2005 by Erik Andersen ++# ++# Licensed under the GPL v2, see the file LICENSE in this tarball. ++ ++ifndef top_srcdir ++top_srcdir=.. ++endif ++ifndef top_builddir ++top_builddir=.. ++endif ++srcdir=$(top_srcdir)/mdadm ++MDADM_DIR:=./ ++include $(top_builddir)/Rules.mak ++include $(top_builddir)/.config ++include Makefile.in ++all: $(libraries-y) ++-include $(top_builddir)/.depend ++ ++clean: ++ rm -f *.o *.a $(AR_TARGET) ++ +diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/mdadm/Makefile.in busybox-1.7.4+gentoo+mdadm/mdadm/Makefile.in +--- busybox-1.7.4+gentoo/mdadm/Makefile.in 1969-12-31 16:00:00.000000000 -0800 ++++ busybox-1.7.4+gentoo+mdadm/mdadm/Makefile.in 2008-03-11 10:31:00.000000000 -0700 +@@ -0,0 +1,31 @@ ++# Makefile for busybox ++# ++# Copyright (C) 1999-2005 by Erik Andersen ++# ++# Licensed under the GPL v2, see the file LICENSE in this tarball. ++ ++MDADM_AR:=mdadm.a ++ifndef $(MDADM_DIR) ++MDADM_DIR:=$(top_builddir)/mdadm/ ++endif ++srcdir=$(top_srcdir)/mdadm ++ ++MDADM-y:= config.o util.o dlink.o sha1.o super0.o super1.o mdexamine.o mdassemble.o ++MDADM-$(CONFIG_MDADM) += mdadm.o ++ ++MDADM_SRC-y:=$(patsubst %.o,$(srcdir)/%.c,$(MDADM-y)) ++MDADM_SRC-a:=$(wildcard $(srcdir)/*.c) ++APPLET_SRC-y+=$(MDADM_SRC-y) ++APPLET_SRC-a+=$(MDADM_SRC-a) ++ ++MDADM-y:=$(sort $(MDADM-y)) ++ ++ifneq ($(strip $(MDADM-y)),) ++libraries-y+=$(MDADM_DIR)$(MDADM_AR) ++endif ++ ++$(MDADM_DIR)$(MDADM_AR): $(patsubst %,$(MDADM_DIR)%, $(MDADM-y)) ++ $(do_ar) ++ ++$(MDADM_DIR)%.o: $(srcdir)/%.c ++ $(compile.c) +diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/mdadm/md5.h busybox-1.7.4+gentoo+mdadm/mdadm/md5.h +--- busybox-1.7.4+gentoo/mdadm/md5.h 1969-12-31 16:00:00.000000000 -0800 ++++ busybox-1.7.4+gentoo+mdadm/mdadm/md5.h 2008-03-11 10:31:00.000000000 -0700 +@@ -0,0 +1,134 @@ ++/* Declaration of functions and data types used for MD5 sum computing ++ library functions. ++ Copyright (C) 1995-1997,1999-2005 Free Software Foundation, Inc. ++ ++ NOTE: The canonical source of this file is maintained with the GNU C ++ Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu. ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms of the GNU General Public License as published by the ++ Free Software Foundation; either version 2, or (at your option) any ++ later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software Foundation, ++ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ ++ ++#ifndef _MD5_H ++#define _MD5_H 1 ++ ++#include ++ ++# include ++#if HAVE_STDINT_H || _LIBC ++# include ++#endif ++ ++#ifndef __GNUC_PREREQ ++# if defined __GNUC__ && defined __GNUC_MINOR__ ++# define __GNUC_PREREQ(maj, min) \ ++ ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) ++# else ++# define __GNUC_PREREQ(maj, min) 0 ++# endif ++#endif ++ ++#ifndef __THROW ++# if defined __cplusplus && __GNUC_PREREQ (2,8) ++# define __THROW throw () ++# else ++# define __THROW ++# endif ++#endif ++ ++#ifndef __attribute__ ++# if ! __GNUC_PREREQ (2,8) || __STRICT_ANSI__ ++# define __attribute__(x) ++# endif ++#endif ++ ++#ifndef _LIBC ++# define __md5_buffer md5_buffer ++# define __md5_finish_ctx md5_finish_ctx ++# define __md5_init_ctx md5_init_ctx ++# define __md5_process_block md5_process_block ++# define __md5_process_bytes md5_process_bytes ++# define __md5_read_ctx md5_read_ctx ++# define __md5_stream md5_stream ++#endif ++ ++typedef uint32_t md5_uint32; ++ ++/* Structure to save state of computation between the single steps. */ ++struct md5_ctx ++{ ++ md5_uint32 A; ++ md5_uint32 B; ++ md5_uint32 C; ++ md5_uint32 D; ++ ++ md5_uint32 total[2]; ++ md5_uint32 buflen; ++ char buffer[128] __attribute__ ((__aligned__ (__alignof__ (md5_uint32)))); ++}; ++ ++/* ++ * The following three functions are build up the low level used in ++ * the functions `md5_stream' and `md5_buffer'. ++ */ ++ ++/* Initialize structure containing state of computation. ++ (RFC 1321, 3.3: Step 3) */ ++extern void __md5_init_ctx (struct md5_ctx *ctx) __THROW; ++ ++/* Starting with the result of former calls of this function (or the ++ initialization function update the context for the next LEN bytes ++ starting at BUFFER. ++ It is necessary that LEN is a multiple of 64!!! */ ++extern void __md5_process_block (const void *buffer, size_t len, ++ struct md5_ctx *ctx) __THROW; ++ ++/* Starting with the result of former calls of this function (or the ++ initialization function update the context for the next LEN bytes ++ starting at BUFFER. ++ It is NOT required that LEN is a multiple of 64. */ ++extern void __md5_process_bytes (const void *buffer, size_t len, ++ struct md5_ctx *ctx) __THROW; ++ ++/* Process the remaining bytes in the buffer and put result from CTX ++ in first 16 bytes following RESBUF. The result is always in little ++ endian byte order, so that a byte-wise output yields to the wanted ++ ASCII representation of the message digest. ++ ++ IMPORTANT: On some systems it is required that RESBUF be correctly ++ aligned for a 32 bits value. */ ++extern void *__md5_finish_ctx (struct md5_ctx *ctx, void *resbuf) __THROW; ++ ++ ++/* Put result from CTX in first 16 bytes following RESBUF. The result is ++ always in little endian byte order, so that a byte-wise output yields ++ to the wanted ASCII representation of the message digest. ++ ++ IMPORTANT: On some systems it is required that RESBUF is correctly ++ aligned for a 32 bits value. */ ++extern void *__md5_read_ctx (const struct md5_ctx *ctx, void *resbuf) __THROW; ++ ++ ++/* Compute MD5 message digest for bytes read from STREAM. The ++ resulting message digest number will be written into the 16 bytes ++ beginning at RESBLOCK. */ ++extern int __md5_stream (FILE *stream, void *resblock) __THROW; ++ ++/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The ++ result is always in little endian byte order, so that a byte-wise ++ output yields to the wanted ASCII representation of the message ++ digest. */ ++extern void *__md5_buffer (const char *buffer, size_t len, ++ void *resblock) __THROW; ++ ++#endif /* md5.h */ +diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/mdadm/mdadm.c busybox-1.7.4+gentoo+mdadm/mdadm/mdadm.c +--- busybox-1.7.4+gentoo/mdadm/mdadm.c 1969-12-31 16:00:00.000000000 -0800 ++++ busybox-1.7.4+gentoo+mdadm/mdadm/mdadm.c 2008-03-11 10:31:00.000000000 -0700 +@@ -0,0 +1,18 @@ ++/* ++ * mdadm support for busybox. ++ * added by Alan Hourihane ++ */ ++#include ++ ++extern int mdassemble_main(int argc, char **argv); ++extern int mdexamine_main(int argc, char **argv); ++ ++int mdadm_main(int argc, char **argv) { ++ if (argc >= 2) { ++ if (!strncmp(argv[1],"--assemble",10)) ++ return mdassemble_main(argc, argv); ++ if (!strncmp(argv[1],"--examine",9)) ++ return mdexamine_main(argc, argv); ++ } ++ return 0; ++} +diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/mdadm/mdadm.h busybox-1.7.4+gentoo+mdadm/mdadm/mdadm.h +--- busybox-1.7.4+gentoo/mdadm/mdadm.h 1969-12-31 16:00:00.000000000 -0800 ++++ busybox-1.7.4+gentoo+mdadm/mdadm/mdadm.h 2008-03-11 10:31:00.000000000 -0700 +@@ -0,0 +1,540 @@ ++/* ++ * mdadm - manage Linux "md" devices aka RAID arrays. ++ * ++ * Copyright (C) 2001-2006 Neil Brown ++ * ++ * ++ * 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: ++ * Paper: Neil Brown ++ * School of Computer Science and Engineering ++ * The University of New South Wales ++ * Sydney, 2052 ++ * Australia ++ */ ++ ++#include ++#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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifdef __dietlibc__ ++#include ++/* dietlibc has deprecated random and srandom!! */ ++#define random rand ++#define srandom srand ++#endif ++ ++ ++#include ++/*#include */ ++#include ++#include ++#include ++#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 ++/* Redhat don't like to #include , and ++ * some time include isn't enough, ++ * and there is no standard conversion function so... */ ++/* And dietlibc doesn't think byteswap is ok, so.. */ ++/* #include */ ++#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 ++# 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 ++#endif ++ ++extern int add_dev(const char *name, const struct stat *stb, int flag, struct FTW *s); ++ ++ ++extern int Manage_ro(char *devname, int fd, int readonly); ++extern int Manage_runstop(char *devname, int fd, int runstop, int quiet); ++extern int Manage_resize(char *devname, int fd, long long size, int raid_disks); ++extern int Manage_reconfig(char *devname, int fd, int layout); ++extern int Manage_subdevs(char *devname, int fd, ++ mddev_dev_t devlist, int verbose); ++extern int autodetect(void); ++extern int Grow_Add_device(char *devname, int fd, char *newdev); ++extern int Grow_addbitmap(char *devname, int fd, char *file, int chunk, int delay, int write_behind, int force); ++extern int Grow_reshape(char *devname, int fd, int quiet, char *backup_file, ++ long long size, ++ int level, int layout, int chunksize, int raid_disks); ++extern int Grow_restart(struct supertype *st, struct mdinfo *info, ++ int *fdlist, int cnt, char *backup_file); ++ ++ ++extern int Assemble(struct supertype *st, char *mddev, int mdfd, ++ mddev_ident_t ident, ++ mddev_dev_t devlist, char *backup_file, ++ int readonly, int runstop, ++ char *update, char *homehost, ++ int verbose, int force); ++ ++extern int Build(char *mddev, int mdfd, int chunk, int level, int layout, ++ int raiddisks, ++ mddev_dev_t devlist, int assume_clean, ++ char *bitmap_file, int bitmap_chunk, int write_behind, int delay, int verbose); ++ ++ ++extern int Create(struct supertype *st, char *mddev, int mdfd, ++ int chunk, int level, int layout, unsigned long long size, int raiddisks, int sparedisks, ++ char *name, char *homehost, int *uuid, ++ int subdevs, mddev_dev_t devlist, ++ int runstop, int verbose, int force, int assume_clean, ++ char *bitmap_file, int bitmap_chunk, int write_behind, int delay); ++ ++extern int Detail(char *dev, int brief, int export, int test, char *homehost); ++extern int Query(char *dev); ++ ++extern int md_get_version(int fd); ++extern int get_linux_version(void); ++extern int parse_uuid(char *str, int uuid[4]); ++extern int check_ext2(int fd, char *name); ++extern int check_reiser(int fd, char *name); ++extern int check_raid(int fd, char *name); ++ ++extern int get_mdp_major(void); ++extern int dev_open(char *dev, int flags); ++extern int is_standard(char *dev, int *nump); ++ ++extern int parse_auto(char *str, char *msg, int config); ++extern mddev_ident_t conf_get_ident(char *dev); ++extern mddev_dev_t conf_get_devs(void); ++extern int conf_test_dev(char *devname); ++extern struct createinfo *conf_get_create_info(void); ++extern void set_conffile(char *file); ++extern char *conf_get_mailaddr(void); ++extern char *conf_get_mailfrom(void); ++extern char *conf_get_program(void); ++extern char *conf_get_homehost(void); ++extern char *conf_line(FILE *file); ++extern char *conf_word(FILE *file, int allow_key); ++extern void free_line(char *line); ++extern int match_oneof(char *devices, char *devname); ++extern void uuid_from_super(int uuid[4], mdp_super_t *super); ++extern int same_uuid(int a[4], int b[4], int swapuuid); ++extern void copy_uuid(void *a, int b[4], int swapuuid); ++/* extern int compare_super(mdp_super_t *first, mdp_super_t *second);*/ ++extern unsigned long calc_csum(void *super, int bytes); ++extern int enough(int level, int raid_disks, int layout, int clean, ++ char *avail, int avail_disks); ++extern int ask(char *mesg); ++extern unsigned long long get_component_size(int fd); ++extern void remove_partitions(int fd); ++ ++ ++extern char *human_size(long long bytes); ++char *human_size_brief(long long bytes); ++ ++extern void put_md_name(char *name); ++extern char *get_md_name(int dev); ++ ++extern char DefaultConfFile[]; ++ ++extern int open_mddev(char *dev, int autof); ++extern int open_mddev_devnum(char *devname, int devnum, char *name, ++ char *chosen_name); ++ ++ ++#define LEVEL_MULTIPATH (-4) ++#define LEVEL_LINEAR (-1) ++#define LEVEL_FAULTY (-5) ++ ++ ++/* faulty stuff */ ++ ++#define WriteTransient 0 ++#define ReadTransient 1 ++#define WritePersistent 2 ++#define ReadPersistent 3 ++#define WriteAll 4 /* doesn't go to device */ ++#define ReadFixable 5 ++#define Modes 6 ++ ++#define ClearErrors 31 ++#define ClearFaults 30 ++ ++#define AllPersist 100 /* internal use only */ ++#define NoPersist 101 ++ ++#define ModeMask 0x1f ++#define ModeShift 5 ++ ++ ++#ifdef __TINYC__ ++#undef minor ++#undef major ++#undef makedev ++#define minor(x) ((x)&0xff) ++#define major(x) (((x)>>8)&0xff) ++#define makedev(M,m) (((M)<<8) | (m)) ++#endif ++ ++/* for raid5 */ ++#define ALGORITHM_LEFT_ASYMMETRIC 0 ++#define ALGORITHM_RIGHT_ASYMMETRIC 1 ++#define ALGORITHM_LEFT_SYMMETRIC 2 ++#define ALGORITHM_RIGHT_SYMMETRIC 3 +diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/mdadm/mdassemble.c busybox-1.7.4+gentoo+mdadm/mdadm/mdassemble.c +--- busybox-1.7.4+gentoo/mdadm/mdassemble.c 1969-12-31 16:00:00.000000000 -0800 ++++ busybox-1.7.4+gentoo+mdadm/mdadm/mdassemble.c 2008-03-11 10:31:00.000000000 -0700 +@@ -0,0 +1,908 @@ ++/* ++ * mdadm - manage Linux "md" devices aka RAID arrays. ++ * ++ * Copyright (C) 2001-2006 Neil Brown ++ * ++ * ++ * 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: ++ * Paper: Neil Brown ++ * School of Computer Science and Engineering ++ * The University of New South Wales ++ * Sydney, 2052 ++ * Australia ++ */ ++ ++#include "mdadm.h" ++#include ++ ++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<= ++ 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=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= 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 && iss->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; iss->update_super(&info, super, "assemble", NULL, verbose, 0, NULL)) { ++ if (force) { ++ if (verbose >= 0) ++ fprintf(stderr, Name ": " ++ "clearing FAULTY flag for device %d in %s for %s\n", ++ j, mddev, devices[j].devname); ++ change = 1; ++ } else { ++ if (verbose >= -1) ++ fprintf(stderr, Name ": " ++ "device %d in %s has wrong state in superblock, but %s seems ok\n", ++ i, mddev, devices[j].devname); ++ } ++ } ++#if 0 ++ if (!devices[j].uptodate && ++ !(super.disks[i].state & (1 << MD_DISK_FAULTY))) { ++ fprintf(stderr, Name ": devices %d of %s is not marked FAULTY in superblock, but cannot be found\n", ++ i, mddev); ++ } ++#endif ++ } ++ if (force && !clean && ++ !enough(info.array.level, info.array.raid_disks, ++ info.array.layout, clean, ++ avail, okcnt)) { ++ change += st->ss->update_super(&info, super, "force-array", ++ devices[chosen_drive].devname, verbose, ++ 0, NULL); ++ clean = 1; ++ } ++ ++ if (change) { ++ int fd; ++ fd = dev_open(devices[chosen_drive].devname, O_RDWR|O_EXCL); ++ if (fd < 0) { ++ fprintf(stderr, Name ": Could not open %s for write - cannot Assemble array.\n", ++ devices[chosen_drive].devname); ++ return 1; ++ } ++ if (st->ss->store_super(st, fd, super)) { ++ close(fd); ++ fprintf(stderr, Name ": Could not re-write superblock on %s\n", ++ devices[chosen_drive].devname); ++ return 1; ++ } ++ close(fd); ++ } ++ ++ /* count number of in-sync devices according to the superblock. ++ * We must have this number to start the array without -s or -R ++ */ ++ req_cnt = info.array.working_disks; ++ ++ /* Almost ready to actually *do* something */ ++ if (!old_linux) { ++ int rv; ++ if ((vers % 100) >= 1) { /* can use different versions */ ++ mdu_array_info_t inf; ++ memset(&inf, 0, sizeof(inf)); ++ inf.major_version = st->ss->major; ++ inf.minor_version = st->minor_version; ++ rv = ioctl(mdfd, SET_ARRAY_INFO, &inf); ++ } else ++ rv = ioctl(mdfd, SET_ARRAY_INFO, NULL); ++ ++ if (rv) { ++ fprintf(stderr, Name ": SET_ARRAY_INFO failed for %s: %s\n", ++ mddev, strerror(errno)); ++ return 1; ++ } ++ if (ident->bitmap_fd >= 0) { ++ if (ioctl(mdfd, SET_BITMAP_FILE, ident->bitmap_fd) != 0) { ++ fprintf(stderr, Name ": SET_BITMAP_FILE failed.\n"); ++ return 1; ++ } ++ } else if (ident->bitmap_file) { ++ /* From config file */ ++ int bmfd = open(ident->bitmap_file, O_RDWR); ++ if (bmfd < 0) { ++ fprintf(stderr, Name ": Could not open bitmap file %s\n", ++ ident->bitmap_file); ++ return 1; ++ } ++ if (ioctl(mdfd, SET_BITMAP_FILE, bmfd) != 0) { ++ fprintf(stderr, Name ": Failed to set bitmapfile for %s\n", mddev); ++ close(bmfd); ++ return 1; ++ } ++ close(bmfd); ++ } ++ ++ /* First, add the raid disks, but add the chosen one last */ ++ for (i=0; i<= bestcnt; i++) { ++ int j; ++ if (i < bestcnt) { ++ j = best[i]; ++ if (j == chosen_drive) ++ continue; ++ } else ++ j = chosen_drive; ++ ++ if (j >= 0 /* && devices[j].uptodate */) { ++ mdu_disk_info_t disk; ++ memset(&disk, 0, sizeof(disk)); ++ disk.major = devices[j].major; ++ disk.minor = devices[j].minor; ++ if (ioctl(mdfd, ADD_NEW_DISK, &disk)!=0) { ++ fprintf(stderr, Name ": failed to add %s to %s: %s\n", ++ devices[j].devname, ++ mddev, ++ strerror(errno)); ++ if (i < info.array.raid_disks || i == bestcnt) ++ okcnt--; ++ else ++ sparecnt--; ++ } else if (verbose > 0) ++ fprintf(stderr, Name ": added %s to %s as %d\n", ++ devices[j].devname, mddev, devices[j].raid_disk); ++ } else if (verbose > 0 && i < info.array.raid_disks) ++ fprintf(stderr, Name ": no uptodate device for slot %d of %s\n", ++ i, mddev); ++ } ++ ++ if (runstop == 1 || ++ (runstop <= 0 && ++ ( enough(info.array.level, info.array.raid_disks, ++ info.array.layout, clean, avail, okcnt) && ++ (okcnt >= req_cnt || start_partial_ok) ++ ))) { ++ if (ioctl(mdfd, RUN_ARRAY, NULL)==0) { ++ if (verbose >= 0) { ++ fprintf(stderr, Name ": %s has been started with %d drive%s", ++ mddev, okcnt, okcnt==1?"":"s"); ++ if (okcnt < info.array.raid_disks) ++ fprintf(stderr, " (out of %d)", info.array.raid_disks); ++ if (sparecnt) ++ fprintf(stderr, " and %d spare%s", sparecnt, sparecnt==1?"":"s"); ++ fprintf(stderr, ".\n"); ++ } ++ return 0; ++ } ++ fprintf(stderr, Name ": failed to RUN_ARRAY %s: %s\n", ++ mddev, strerror(errno)); ++ ++ if (!enough(info.array.level, info.array.raid_disks, ++ info.array.layout, 1, avail, okcnt)) ++ fprintf(stderr, Name ": Not enough devices to " ++ "start the array.\n"); ++ else if (!enough(info.array.level, ++ info.array.raid_disks, ++ info.array.layout, clean, ++ avail, okcnt)) ++ fprintf(stderr, Name ": Not enough devices to " ++ "start the array while not clean " ++ "- consider --force.\n"); ++ ++ return 1; ++ } ++ if (runstop == -1) { ++ fprintf(stderr, Name ": %s assembled from %d drive%s", ++ mddev, okcnt, okcnt==1?"":"s"); ++ if (okcnt != info.array.raid_disks) ++ fprintf(stderr, " (out of %d)", info.array.raid_disks); ++ fprintf(stderr, ", but not started.\n"); ++ return 0; ++ } ++ if (verbose >= -1) { ++ fprintf(stderr, Name ": %s assembled from %d drive%s", mddev, okcnt, okcnt==1?"":"s"); ++ if (sparecnt) ++ fprintf(stderr, " and %d spare%s", sparecnt, sparecnt==1?"":"s"); ++ if (!enough(info.array.level, info.array.raid_disks, ++ info.array.layout, 1, avail, okcnt)) ++ fprintf(stderr, " - not enough to start the array.\n"); ++ else if (!enough(info.array.level, ++ info.array.raid_disks, ++ info.array.layout, clean, ++ avail, okcnt)) ++ fprintf(stderr, " - not enough to start the " ++ "array while not clean - consider " ++ "--force.\n"); ++ else { ++ if (req_cnt == info.array.raid_disks) ++ fprintf(stderr, " - need all %d to start it", req_cnt); ++ else ++ fprintf(stderr, " - need %d of %d to start", req_cnt, info.array.raid_disks); ++ fprintf(stderr, " (use --run to insist).\n"); ++ } ++ } ++ return 1; ++ } else { ++ /* The "chosen_drive" is a good choice, and if necessary, the superblock has ++ * been updated to point to the current locations of devices. ++ * so we can just start the array ++ */ ++ unsigned long dev; ++ dev = makedev(devices[chosen_drive].major, ++ devices[chosen_drive].minor); ++ if (ioctl(mdfd, START_ARRAY, dev)) { ++ fprintf(stderr, Name ": Cannot start array: %s\n", ++ strerror(errno)); ++ } ++ ++ } ++ return 0; ++} ++ ++int mdfd = -1; ++int runstop = 0; ++int readonly = 0; ++int verbose = 0; ++int force = 0; ++ ++int mdassemble_main(int argc, char **argv) { ++ mddev_ident_t array_list = conf_get_ident(NULL); ++ int minor; ++ if (!array_list) { ++ fprintf(stderr, Name ": No arrays found in config file\n"); ++ return 1; ++ } else { ++ for (; array_list; array_list = array_list->next) { ++ mdu_array_info_t array; ++ if (!strncmp("/dev/md", array_list->devname, 7)) { ++ errno = 0; ++ minor = strtoul(array_list->devname + 7, NULL, 0); ++ if (!errno) { ++ mknod(array_list->devname, S_IFBLK|0600, makedev(MD_MAJOR, minor)); ++ } ++ } ++ mdfd = open_mddev(array_list->devname, array_list->autof); ++ if (mdfd < 0) { ++ ++ fprintf(stderr, Name ": failed to open array\n"); ++ continue; ++ } ++ if (ioctl(mdfd, GET_ARRAY_INFO, &array) < 0) { ++ Assemble(array_list->st, array_list->devname, mdfd, ++ array_list, NULL, NULL, ++ readonly, runstop, NULL, NULL, verbose, force); ++ } ++ close(mdfd); ++ } ++ } ++ return 0; ++} ++ +diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/mdadm/mdexamine.c busybox-1.7.4+gentoo+mdadm/mdadm/mdexamine.c +--- busybox-1.7.4+gentoo/mdadm/mdexamine.c 1969-12-31 16:00:00.000000000 -0800 ++++ busybox-1.7.4+gentoo+mdadm/mdadm/mdexamine.c 2008-03-11 10:31:00.000000000 -0700 +@@ -0,0 +1,157 @@ ++/* ++ * mdadm - manage Linux "md" devices aka RAID arrays. ++ * ++ * Copyright (C) 2001-2006 Neil Brown ++ * ++ * ++ * 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: ++ * Paper: Neil Brown ++ * School of Computer Science and Engineering ++ * The University of New South Wales ++ * Sydney, 2052 ++ * Australia ++ */ ++ ++#include "mdadm.h" ++#include "dlink.h" ++ ++#if ! defined(__BIG_ENDIAN) && ! defined(__LITTLE_ENDIAN) ++#error no endian defined ++#endif ++#include "md_u.h" ++#include "md_p.h" ++ ++static int Examine(mddev_dev_t devlist, int brief, int scan, ++ int SparcAdjust, struct supertype *forcest, ++ char *homehost) ++{ ++ ++ /* Read the raid superblock from a device and ++ * display important content. ++ * ++ * If cannot be found, print reason: too small, bad magic ++ * ++ * Print: ++ * version, ctime, level, size, raid+spare+ ++ * prefered minor ++ * uuid ++ * ++ * utime, state etc ++ * ++ * If (brief) gather devices for same array and just print a mdadm.conf line including devices= ++ * if devlist==NULL, use conf_get_devs() ++ */ ++ int fd; ++ void *super = NULL; ++ int rv = 0; ++ int err = 0; ++ ++ struct array { ++ void *super; ++ struct supertype *st; ++ struct mdinfo info; ++ void *devs; ++ struct array *next; ++ int spares; ++ } *arrays = NULL; ++ ++ for (; devlist ; devlist=devlist->next) { ++ struct supertype *st = forcest; ++ ++ fd = dev_open(devlist->devname, O_RDONLY); ++ if (fd < 0) { ++ if (!scan) { ++ fprintf(stderr,Name ": cannot open %s: %s\n", ++ devlist->devname, strerror(errno)); ++ rv = 1; ++ } ++ err = 1; ++ } ++ else { ++ if (!st) ++ st = guess_super(fd); ++ if (st) ++ err = st->ss->load_super(st, fd, &super, (brief||scan)?NULL:devlist->devname); ++ else { ++ if (!brief) { ++ fprintf(stderr, Name ": No md superblock detected on %s.\n", devlist->devname); ++ rv = 1; ++ } ++ err = 1; ++ } ++ close(fd); ++ } ++ if (err) ++ continue; ++ ++ if (SparcAdjust) ++ st->ss->update_super(NULL, super, "sparc2.2", devlist->devname, 0, 0, NULL); ++ /* Ok, its good enough to try, though the checksum could be wrong */ ++ if (brief) { ++ struct array *ap; ++ char *d; ++ for (ap=arrays; ap; ap=ap->next) { ++ if (st->ss == ap->st->ss && st->ss->compare_super(&ap->super, super)==0) ++ break; ++ } ++ if (!ap) { ++ ap = malloc(sizeof(*ap)); ++ ap->super = super; ++ ap->devs = dl_head(); ++ ap->next = arrays; ++ ap->spares = 0; ++ ap->st = st; ++ arrays = ap; ++ st->ss->getinfo_super(&ap->info, super); ++ } else { ++ st->ss->getinfo_super(&ap->info, super); ++ free(super); ++ } ++ if (!(ap->info.disk.state & MD_DISK_SYNC)) ++ ap->spares++; ++ d = dl_strdup(devlist->devname); ++ dl_add(ap->devs, d); ++ } ++ } ++ if (brief) { ++ struct array *ap; ++ for (ap=arrays; ap; ap=ap->next) { ++ char sep='='; ++ char *d; ++ ap->st->ss->brief_examine_super(ap->super); ++ if (ap->spares) printf(" spares=%d", ap->spares); ++ if (brief > 1) { ++ printf(" devices"); ++ for (d=dl_next(ap->devs); d!= ap->devs; d=dl_next(d)) { ++ printf("%c%s", sep, d); ++ sep=','; ++ } ++ } ++ free(ap->super); ++ /* FIXME free ap */ ++ if (ap->spares || brief > 1) ++ printf("\n"); ++ } ++ } ++ return rv; ++} ++ ++int mdexamine_main(int argc, char **argv) { ++ return Examine(conf_get_devs(), 1, 0, 0, NULL, NULL); ++} ++ +diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/mdadm/md_p.h busybox-1.7.4+gentoo+mdadm/mdadm/md_p.h +--- busybox-1.7.4+gentoo/mdadm/md_p.h 1969-12-31 16:00:00.000000000 -0800 ++++ busybox-1.7.4+gentoo+mdadm/mdadm/md_p.h 2008-03-11 10:31:00.000000000 -0700 +@@ -0,0 +1,194 @@ ++/* ++ md_p.h : physical layout of Linux RAID devices ++ Copyright (C) 1996-98 Ingo Molnar, Gadi Oxman ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2, or (at your option) ++ any later version. ++ ++ You should have received a copy of the GNU General Public License ++ (for example /usr/src/linux/COPYING); if not, write to the Free ++ Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++*/ ++ ++#ifndef _MD_P_H ++#define _MD_P_H ++ ++/* ++ * RAID superblock. ++ * ++ * The RAID superblock maintains some statistics on each RAID configuration. ++ * Each real device in the RAID set contains it near the end of the device. ++ * Some of the ideas are copied from the ext2fs implementation. ++ * ++ * We currently use 4096 bytes as follows: ++ * ++ * word offset function ++ * ++ * 0 - 31 Constant generic RAID device information. ++ * 32 - 63 Generic state information. ++ * 64 - 127 Personality specific information. ++ * 128 - 511 12 32-words descriptors of the disks in the raid set. ++ * 512 - 911 Reserved. ++ * 912 - 1023 Disk specific descriptor. ++ */ ++ ++/* ++ * If x is the real device size in bytes, we return an apparent size of: ++ * ++ * y = (x & ~(MD_RESERVED_BYTES - 1)) - MD_RESERVED_BYTES ++ * ++ * and place the 4kB superblock at offset y. ++ */ ++#define MD_RESERVED_BYTES (64 * 1024) ++#define MD_RESERVED_SECTORS (MD_RESERVED_BYTES / 512) ++#define MD_RESERVED_BLOCKS (MD_RESERVED_BYTES / BLOCK_SIZE) ++ ++#define MD_NEW_SIZE_SECTORS(x) ((x & ~(MD_RESERVED_SECTORS - 1)) - MD_RESERVED_SECTORS) ++#define MD_NEW_SIZE_BLOCKS(x) ((x & ~(MD_RESERVED_BLOCKS - 1)) - MD_RESERVED_BLOCKS) ++ ++#define MD_SB_BYTES 4096 ++#define MD_SB_WORDS (MD_SB_BYTES / 4) ++#define MD_SB_BLOCKS (MD_SB_BYTES / BLOCK_SIZE) ++#define MD_SB_SECTORS (MD_SB_BYTES / 512) ++ ++/* ++ * The following are counted in 32-bit words ++ */ ++#define MD_SB_GENERIC_OFFSET 0 ++#define MD_SB_PERSONALITY_OFFSET 64 ++#define MD_SB_DISKS_OFFSET 128 ++#define MD_SB_DESCRIPTOR_OFFSET 992 ++ ++#define MD_SB_GENERIC_CONSTANT_WORDS 32 ++#define MD_SB_GENERIC_STATE_WORDS 32 ++#define MD_SB_GENERIC_WORDS (MD_SB_GENERIC_CONSTANT_WORDS + MD_SB_GENERIC_STATE_WORDS) ++#define MD_SB_PERSONALITY_WORDS 64 ++#define MD_SB_DESCRIPTOR_WORDS 32 ++#define MD_SB_DISKS 27 ++#define MD_SB_DISKS_WORDS (MD_SB_DISKS*MD_SB_DESCRIPTOR_WORDS) ++#define MD_SB_RESERVED_WORDS (1024 - MD_SB_GENERIC_WORDS - MD_SB_PERSONALITY_WORDS - MD_SB_DISKS_WORDS - MD_SB_DESCRIPTOR_WORDS) ++#define MD_SB_EQUAL_WORDS (MD_SB_GENERIC_WORDS + MD_SB_PERSONALITY_WORDS + MD_SB_DISKS_WORDS) ++ ++/* ++ * Device "operational" state bits ++ */ ++#define MD_DISK_FAULTY 0 /* disk is faulty / operational */ ++#define MD_DISK_ACTIVE 1 /* disk is running or spare disk */ ++#define MD_DISK_SYNC 2 /* disk is in sync with the raid set */ ++#define MD_DISK_REMOVED 3 /* disk is in sync with the raid set */ ++ ++#define MD_DISK_WRITEMOSTLY 9 /* disk is "write-mostly" is RAID1 config. ++ * read requests will only be sent here in ++ * dire need ++ */ ++ ++typedef struct mdp_device_descriptor_s { ++ __u32 number; /* 0 Device number in the entire set */ ++ __u32 major; /* 1 Device major number */ ++ __u32 minor; /* 2 Device minor number */ ++ __u32 raid_disk; /* 3 The role of the device in the raid set */ ++ __u32 state; /* 4 Operational state */ ++ __u32 reserved[MD_SB_DESCRIPTOR_WORDS - 5]; ++} mdp_disk_t; ++ ++#define MD_SB_MAGIC 0xa92b4efc ++ ++/* ++ * Superblock state bits ++ */ ++#define MD_SB_CLEAN 0 ++#define MD_SB_ERRORS 1 ++ ++#define MD_SB_BITMAP_PRESENT 8 /* bitmap may be present nearby */ ++ ++typedef struct mdp_superblock_s { ++ /* ++ * Constant generic information ++ */ ++ __u32 md_magic; /* 0 MD identifier */ ++ __u32 major_version; /* 1 major version to which the set conforms */ ++ __u32 minor_version; /* 2 minor version ... */ ++ __u32 patch_version; /* 3 patchlevel version ... */ ++ __u32 gvalid_words; /* 4 Number of used words in this section */ ++ __u32 set_uuid0; /* 5 Raid set identifier */ ++ __u32 ctime; /* 6 Creation time */ ++ __u32 level; /* 7 Raid personality */ ++ __u32 size; /* 8 Apparent size of each individual disk */ ++ __u32 nr_disks; /* 9 total disks in the raid set */ ++ __u32 raid_disks; /* 10 disks in a fully functional raid set */ ++ __u32 md_minor; /* 11 preferred MD minor device number */ ++ __u32 not_persistent; /* 12 does it have a persistent superblock */ ++ __u32 set_uuid1; /* 13 Raid set identifier #2 */ ++ __u32 set_uuid2; /* 14 Raid set identifier #3 */ ++ __u32 set_uuid3; /* 15 Raid set identifier #4 */ ++ __u32 gstate_creserved[MD_SB_GENERIC_CONSTANT_WORDS - 16]; ++ ++ /* ++ * Generic state information ++ */ ++ __u32 utime; /* 0 Superblock update time */ ++ __u32 state; /* 1 State bits (clean, ...) */ ++ __u32 active_disks; /* 2 Number of currently active disks */ ++ __u32 working_disks; /* 3 Number of working disks */ ++ __u32 failed_disks; /* 4 Number of failed disks */ ++ __u32 spare_disks; /* 5 Number of spare disks */ ++ __u32 sb_csum; /* 6 checksum of the whole superblock */ ++#if __BYTE_ORDER == __BIG_ENDIAN ++ __u32 events_hi; /* 7 high-order of superblock update count */ ++ __u32 events_lo; /* 8 low-order of superblock update count */ ++ __u32 cp_events_hi; /* 9 high-order of checkpoint update count */ ++ __u32 cp_events_lo; /* 10 low-order of checkpoint update count */ ++#else ++ __u32 events_lo; /* 7 low-order of superblock update count */ ++ __u32 events_hi; /* 8 high-order of superblock update count */ ++ __u32 cp_events_lo; /* 9 low-order of checkpoint update count */ ++ __u32 cp_events_hi; /* 10 high-order of checkpoint update count */ ++#endif ++ __u32 recovery_cp; /* 11 recovery checkpoint sector count */ ++ /* There are only valid for minor_version > 90 */ ++ __u64 reshape_position; /* 12,13 next address in array-space for reshape */ ++ __u32 new_level; /* 14 new level we are reshaping to */ ++ __u32 delta_disks; /* 15 change in number of raid_disks */ ++ __u32 new_layout; /* 16 new layout */ ++ __u32 new_chunk; /* 17 new chunk size (bytes) */ ++ __u32 gstate_sreserved[MD_SB_GENERIC_STATE_WORDS - 18]; ++ ++ /* ++ * Personality information ++ */ ++ __u32 layout; /* 0 the array's physical layout */ ++ __u32 chunk_size; /* 1 chunk size in bytes */ ++ __u32 root_pv; /* 2 LV root PV */ ++ __u32 root_block; /* 3 LV root block */ ++ __u32 pstate_reserved[MD_SB_PERSONALITY_WORDS - 4]; ++ ++ /* ++ * Disks information ++ */ ++ mdp_disk_t disks[MD_SB_DISKS]; ++ ++ /* ++ * Reserved ++ */ ++ __u32 reserved[MD_SB_RESERVED_WORDS]; ++ ++ /* ++ * Active descriptor ++ */ ++ mdp_disk_t this_disk; ++ ++} mdp_super_t; ++ ++#ifdef __TINYC__ ++typedef unsigned long long __u64; ++#endif ++ ++static inline __u64 md_event(mdp_super_t *sb) { ++ __u64 ev = sb->events_hi; ++ return (ev<<32)| sb->events_lo; ++} ++ ++#endif ++ +diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/mdadm/md_u.h busybox-1.7.4+gentoo+mdadm/mdadm/md_u.h +--- busybox-1.7.4+gentoo/mdadm/md_u.h 1969-12-31 16:00:00.000000000 -0800 ++++ busybox-1.7.4+gentoo+mdadm/mdadm/md_u.h 2008-03-11 10:31:00.000000000 -0700 +@@ -0,0 +1,123 @@ ++/* ++ md_u.h : user <=> kernel API between Linux raidtools and RAID drivers ++ Copyright (C) 1998 Ingo Molnar ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2, or (at your option) ++ any later version. ++ ++ You should have received a copy of the GNU General Public License ++ (for example /usr/src/linux/COPYING); if not, write to the Free ++ Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++*/ ++ ++#ifndef _MD_U_H ++#define _MD_U_H ++ ++/* ioctls */ ++ ++/* status */ ++#define RAID_VERSION _IOR (MD_MAJOR, 0x10, mdu_version_t) ++#define GET_ARRAY_INFO _IOR (MD_MAJOR, 0x11, mdu_array_info_t) ++#define GET_DISK_INFO _IOR (MD_MAJOR, 0x12, mdu_disk_info_t) ++#define PRINT_RAID_DEBUG _IO (MD_MAJOR, 0x13) ++#define RAID_AUTORUN _IO (MD_MAJOR, 0x14) ++#define GET_BITMAP_FILE _IOR (MD_MAJOR, 0x15, mdu_bitmap_file_t) ++ ++/* configuration */ ++#define CLEAR_ARRAY _IO (MD_MAJOR, 0x20) ++#define ADD_NEW_DISK _IOW (MD_MAJOR, 0x21, mdu_disk_info_t) ++#define HOT_REMOVE_DISK _IO (MD_MAJOR, 0x22) ++#define SET_ARRAY_INFO _IOW (MD_MAJOR, 0x23, mdu_array_info_t) ++#define SET_DISK_INFO _IO (MD_MAJOR, 0x24) ++#define WRITE_RAID_INFO _IO (MD_MAJOR, 0x25) ++#define UNPROTECT_ARRAY _IO (MD_MAJOR, 0x26) ++#define PROTECT_ARRAY _IO (MD_MAJOR, 0x27) ++#define HOT_ADD_DISK _IO (MD_MAJOR, 0x28) ++#define SET_DISK_FAULTY _IO (MD_MAJOR, 0x29) ++#define SET_BITMAP_FILE _IOW (MD_MAJOR, 0x2b, int) ++ ++/* usage */ ++#define RUN_ARRAY _IOW (MD_MAJOR, 0x30, mdu_param_t) ++#define START_ARRAY _IO (MD_MAJOR, 0x31) ++#define STOP_ARRAY _IO (MD_MAJOR, 0x32) ++#define STOP_ARRAY_RO _IO (MD_MAJOR, 0x33) ++#define RESTART_ARRAY_RW _IO (MD_MAJOR, 0x34) ++ ++typedef struct mdu_version_s { ++ int major; ++ int minor; ++ int patchlevel; ++} mdu_version_t; ++ ++typedef struct mdu_array_info_s { ++ /* ++ * Generic constant information ++ */ ++ int major_version; ++ int minor_version; ++ int patch_version; ++ int ctime; ++ int level; ++ int size; ++ int nr_disks; ++ int raid_disks; ++ int md_minor; ++ int not_persistent; ++ ++ /* ++ * Generic state information ++ */ ++ int utime; /* 0 Superblock update time */ ++ int state; /* 1 State bits (clean, ...) */ ++ int active_disks; /* 2 Number of currently active disks */ ++ int working_disks; /* 3 Number of working disks */ ++ int failed_disks; /* 4 Number of failed disks */ ++ int spare_disks; /* 5 Number of spare disks */ ++ ++ /* ++ * Personality information ++ */ ++ int layout; /* 0 the array's physical layout */ ++ int chunk_size; /* 1 chunk size in bytes */ ++ ++} mdu_array_info_t; ++ ++typedef struct mdu_disk_info_s { ++ /* ++ * configuration/status of one particular disk ++ */ ++ int number; ++ int major; ++ int minor; ++ int raid_disk; ++ int state; ++ ++} mdu_disk_info_t; ++ ++typedef struct mdu_start_info_s { ++ /* ++ * configuration/status of one particular disk ++ */ ++ int major; ++ int minor; ++ int raid_disk; ++ int state; ++ ++} mdu_start_info_t; ++ ++typedef struct mdu_bitmap_file_s ++{ ++ char pathname[4096]; ++} mdu_bitmap_file_t; ++ ++typedef struct mdu_param_s ++{ ++ int personality; /* 1,2,3,4 */ ++ int chunk_size; /* in bytes */ ++ int max_fault; /* unused for now */ ++} mdu_param_t; ++ ++#endif ++ +diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/mdadm/sha1.c busybox-1.7.4+gentoo+mdadm/mdadm/sha1.c +--- busybox-1.7.4+gentoo/mdadm/sha1.c 1969-12-31 16:00:00.000000000 -0800 ++++ busybox-1.7.4+gentoo+mdadm/mdadm/sha1.c 2008-03-11 10:31:00.000000000 -0700 +@@ -0,0 +1,423 @@ ++/* sha1.c - Functions to compute SHA1 message digest of files or ++ memory blocks according to the NIST specification FIPS-180-1. ++ ++ Copyright (C) 2000, 2001, 2003, 2004, 2005 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms of the GNU General Public License as published by the ++ Free Software Foundation; either version 2, or (at your option) any ++ later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software Foundation, ++ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ ++ ++/* Written by Scott G. Miller ++ Credits: ++ Robert Klep -- Expansion function fix ++*/ ++ ++#ifdef HAVE_CONFIG_H ++# include ++#endif ++ ++#include "sha1.h" ++ ++#include ++#include ++ ++#if USE_UNLOCKED_IO ++# include "unlocked-io.h" ++#endif ++ ++/* SWAP does an endian swap on architectures that are little-endian, ++ as SHA1 needs some data in a big-endian form. */ ++ ++#ifdef WORDS_BIGENDIAN ++# define SWAP(n) (n) ++#else ++# define SWAP(n) \ ++ (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) ++#endif ++ ++#define BLOCKSIZE 4096 ++#if BLOCKSIZE % 64 != 0 ++# error "invalid BLOCKSIZE" ++#endif ++ ++/* This array contains the bytes used to pad the buffer to the next ++ 64-byte boundary. (RFC 1321, 3.1: Step 1) */ ++static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; ++ ++ ++/* ++ Takes a pointer to a 160 bit block of data (five 32 bit ints) and ++ intializes it to the start constants of the SHA1 algorithm. This ++ must be called before using hash in the call to sha1_hash. ++*/ ++void ++sha1_init_ctx (struct sha1_ctx *ctx) ++{ ++ ctx->A = 0x67452301; ++ ctx->B = 0xefcdab89; ++ ctx->C = 0x98badcfe; ++ ctx->D = 0x10325476; ++ ctx->E = 0xc3d2e1f0; ++ ++ ctx->total[0] = ctx->total[1] = 0; ++ ctx->buflen = 0; ++} ++ ++/* Put result from CTX in first 20 bytes following RESBUF. The result ++ must be in little endian byte order. ++ ++ IMPORTANT: On some systems it is required that RESBUF is correctly ++ aligned for a 32 bits value. */ ++void * ++sha1_read_ctx (const struct sha1_ctx *ctx, void *resbuf) ++{ ++ ((md5_uint32 *) resbuf)[0] = SWAP (ctx->A); ++ ((md5_uint32 *) resbuf)[1] = SWAP (ctx->B); ++ ((md5_uint32 *) resbuf)[2] = SWAP (ctx->C); ++ ((md5_uint32 *) resbuf)[3] = SWAP (ctx->D); ++ ((md5_uint32 *) resbuf)[4] = SWAP (ctx->E); ++ ++ return resbuf; ++} ++ ++/* Process the remaining bytes in the internal buffer and the usual ++ prolog according to the standard and write the result to RESBUF. ++ ++ IMPORTANT: On some systems it is required that RESBUF is correctly ++ aligned for a 32 bits value. */ ++void * ++sha1_finish_ctx (struct sha1_ctx *ctx, void *resbuf) ++{ ++ /* Take yet unprocessed bytes into account. */ ++ md5_uint32 bytes = ctx->buflen; ++ size_t pad; ++ ++ /* Now count remaining bytes. */ ++ ctx->total[0] += bytes; ++ if (ctx->total[0] < bytes) ++ ++ctx->total[1]; ++ ++ pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes; ++ memcpy (&ctx->buffer[bytes], fillbuf, pad); ++ ++ /* Put the 64-bit file length in *bits* at the end of the buffer. */ ++ *(md5_uint32 *) &ctx->buffer[bytes + pad + 4] = SWAP (ctx->total[0] << 3); ++ *(md5_uint32 *) &ctx->buffer[bytes + pad] = SWAP ((ctx->total[1] << 3) | ++ (ctx->total[0] >> 29)); ++ ++ /* Process last bytes. */ ++ sha1_process_block (ctx->buffer, bytes + pad + 8, ctx); ++ ++ return sha1_read_ctx (ctx, resbuf); ++} ++ ++/* Compute SHA1 message digest for bytes read from STREAM. The ++ resulting message digest number will be written into the 16 bytes ++ beginning at RESBLOCK. */ ++int ++sha1_stream (FILE *stream, void *resblock) ++{ ++ struct sha1_ctx ctx; ++ char buffer[BLOCKSIZE + 72]; ++ size_t sum; ++ ++ /* Initialize the computation context. */ ++ sha1_init_ctx (&ctx); ++ ++ /* Iterate over full file contents. */ ++ while (1) ++ { ++ /* We read the file in blocks of BLOCKSIZE bytes. One call of the ++ computation function processes the whole buffer so that with the ++ next round of the loop another block can be read. */ ++ size_t n; ++ sum = 0; ++ ++ /* Read block. Take care for partial reads. */ ++ while (1) ++ { ++ n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); ++ ++ sum += n; ++ ++ if (sum == BLOCKSIZE) ++ break; ++ ++ if (n == 0) ++ { ++ /* Check for the error flag IFF N == 0, so that we don't ++ exit the loop after a partial read due to e.g., EAGAIN ++ or EWOULDBLOCK. */ ++ if (ferror (stream)) ++ return 1; ++ goto process_partial_block; ++ } ++ ++ /* We've read at least one byte, so ignore errors. But always ++ check for EOF, since feof may be true even though N > 0. ++ Otherwise, we could end up calling fread after EOF. */ ++ if (feof (stream)) ++ goto process_partial_block; ++ } ++ ++ /* Process buffer with BLOCKSIZE bytes. Note that ++ BLOCKSIZE % 64 == 0 ++ */ ++ sha1_process_block (buffer, BLOCKSIZE, &ctx); ++ } ++ ++ process_partial_block:; ++ ++ /* Process any remaining bytes. */ ++ if (sum > 0) ++ sha1_process_bytes (buffer, sum, &ctx); ++ ++ /* Construct result in desired memory. */ ++ sha1_finish_ctx (&ctx, resblock); ++ return 0; ++} ++ ++/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The ++ result is always in little endian byte order, so that a byte-wise ++ output yields to the wanted ASCII representation of the message ++ digest. */ ++void * ++sha1_buffer (const char *buffer, size_t len, void *resblock) ++{ ++ struct sha1_ctx ctx; ++ ++ /* Initialize the computation context. */ ++ sha1_init_ctx (&ctx); ++ ++ /* Process whole buffer but last len % 64 bytes. */ ++ sha1_process_bytes (buffer, len, &ctx); ++ ++ /* Put result in desired memory area. */ ++ return sha1_finish_ctx (&ctx, resblock); ++} ++ ++void ++sha1_process_bytes (const void *buffer, size_t len, struct sha1_ctx *ctx) ++{ ++ /* When we already have some bits in our internal buffer concatenate ++ both inputs first. */ ++ if (ctx->buflen != 0) ++ { ++ size_t left_over = ctx->buflen; ++ size_t add = 128 - left_over > len ? len : 128 - left_over; ++ ++ memcpy (&ctx->buffer[left_over], buffer, add); ++ ctx->buflen += add; ++ ++ if (ctx->buflen > 64) ++ { ++ sha1_process_block (ctx->buffer, ctx->buflen & ~63, ctx); ++ ++ ctx->buflen &= 63; ++ /* The regions in the following copy operation cannot overlap. */ ++ memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63], ++ ctx->buflen); ++ } ++ ++ buffer = (const char *) buffer + add; ++ len -= add; ++ } ++ ++ /* Process available complete blocks. */ ++ if (len >= 64) ++ { ++#if !_STRING_ARCH_unaligned ++# define alignof(type) offsetof (struct { char c; type x; }, x) ++# define UNALIGNED_P(p) (((size_t) p) % alignof (md5_uint32) != 0) ++ if (UNALIGNED_P (buffer)) ++ while (len > 64) ++ { ++ sha1_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx); ++ buffer = (const char *) buffer + 64; ++ len -= 64; ++ } ++ else ++#endif ++ { ++ sha1_process_block (buffer, len & ~63, ctx); ++ buffer = (const char *) buffer + (len & ~63); ++ len &= 63; ++ } ++ } ++ ++ /* Move remaining bytes in internal buffer. */ ++ if (len > 0) ++ { ++ size_t left_over = ctx->buflen; ++ ++ memcpy (&ctx->buffer[left_over], buffer, len); ++ left_over += len; ++ if (left_over >= 64) ++ { ++ sha1_process_block (ctx->buffer, 64, ctx); ++ left_over -= 64; ++ memcpy (ctx->buffer, &ctx->buffer[64], left_over); ++ } ++ ctx->buflen = left_over; ++ } ++} ++ ++/* --- Code below is the primary difference between md5.c and sha1.c --- */ ++ ++/* SHA1 round constants */ ++#define K1 0x5a827999L ++#define K2 0x6ed9eba1L ++#define K3 0x8f1bbcdcL ++#define K4 0xca62c1d6L ++ ++/* Round functions. Note that F2 is the same as F4. */ ++#define F1(B,C,D) ( D ^ ( B & ( C ^ D ) ) ) ++#define F2(B,C,D) (B ^ C ^ D) ++#define F3(B,C,D) ( ( B & C ) | ( D & ( B | C ) ) ) ++#define F4(B,C,D) (B ^ C ^ D) ++ ++/* Process LEN bytes of BUFFER, accumulating context into CTX. ++ It is assumed that LEN % 64 == 0. ++ Most of this code comes from GnuPG's cipher/sha1.c. */ ++ ++void ++sha1_process_block (const void *buffer, size_t len, struct sha1_ctx *ctx) ++{ ++ const md5_uint32 *words = buffer; ++ size_t nwords = len / sizeof (md5_uint32); ++ const md5_uint32 *endp = words + nwords; ++ md5_uint32 x[16]; ++ md5_uint32 a = ctx->A; ++ md5_uint32 b = ctx->B; ++ md5_uint32 c = ctx->C; ++ md5_uint32 d = ctx->D; ++ md5_uint32 e = ctx->E; ++ ++ /* First increment the byte count. RFC 1321 specifies the possible ++ length of the file up to 2^64 bits. Here we only compute the ++ number of bytes. Do a double word increment. */ ++ ctx->total[0] += len; ++ if (ctx->total[0] < len) ++ ++ctx->total[1]; ++ ++#define rol(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) ++ ++#define M(I) ( tm = x[I&0x0f] ^ x[(I-14)&0x0f] \ ++ ^ x[(I-8)&0x0f] ^ x[(I-3)&0x0f] \ ++ , (x[I&0x0f] = rol(tm, 1)) ) ++ ++#define R(A,B,C,D,E,F,K,M) do { E += rol( A, 5 ) \ ++ + F( B, C, D ) \ ++ + K \ ++ + M; \ ++ B = rol( B, 30 ); \ ++ } while(0) ++ ++ while (words < endp) ++ { ++ md5_uint32 tm; ++ int t; ++ for (t = 0; t < 16; t++) ++ { ++ x[t] = SWAP (*words); ++ words++; ++ } ++ ++ R( a, b, c, d, e, F1, K1, x[ 0] ); ++ R( e, a, b, c, d, F1, K1, x[ 1] ); ++ R( d, e, a, b, c, F1, K1, x[ 2] ); ++ R( c, d, e, a, b, F1, K1, x[ 3] ); ++ R( b, c, d, e, a, F1, K1, x[ 4] ); ++ R( a, b, c, d, e, F1, K1, x[ 5] ); ++ R( e, a, b, c, d, F1, K1, x[ 6] ); ++ R( d, e, a, b, c, F1, K1, x[ 7] ); ++ R( c, d, e, a, b, F1, K1, x[ 8] ); ++ R( b, c, d, e, a, F1, K1, x[ 9] ); ++ R( a, b, c, d, e, F1, K1, x[10] ); ++ R( e, a, b, c, d, F1, K1, x[11] ); ++ R( d, e, a, b, c, F1, K1, x[12] ); ++ R( c, d, e, a, b, F1, K1, x[13] ); ++ R( b, c, d, e, a, F1, K1, x[14] ); ++ R( a, b, c, d, e, F1, K1, x[15] ); ++ R( e, a, b, c, d, F1, K1, M(16) ); ++ R( d, e, a, b, c, F1, K1, M(17) ); ++ R( c, d, e, a, b, F1, K1, M(18) ); ++ R( b, c, d, e, a, F1, K1, M(19) ); ++ R( a, b, c, d, e, F2, K2, M(20) ); ++ R( e, a, b, c, d, F2, K2, M(21) ); ++ R( d, e, a, b, c, F2, K2, M(22) ); ++ R( c, d, e, a, b, F2, K2, M(23) ); ++ R( b, c, d, e, a, F2, K2, M(24) ); ++ R( a, b, c, d, e, F2, K2, M(25) ); ++ R( e, a, b, c, d, F2, K2, M(26) ); ++ R( d, e, a, b, c, F2, K2, M(27) ); ++ R( c, d, e, a, b, F2, K2, M(28) ); ++ R( b, c, d, e, a, F2, K2, M(29) ); ++ R( a, b, c, d, e, F2, K2, M(30) ); ++ R( e, a, b, c, d, F2, K2, M(31) ); ++ R( d, e, a, b, c, F2, K2, M(32) ); ++ R( c, d, e, a, b, F2, K2, M(33) ); ++ R( b, c, d, e, a, F2, K2, M(34) ); ++ R( a, b, c, d, e, F2, K2, M(35) ); ++ R( e, a, b, c, d, F2, K2, M(36) ); ++ R( d, e, a, b, c, F2, K2, M(37) ); ++ R( c, d, e, a, b, F2, K2, M(38) ); ++ R( b, c, d, e, a, F2, K2, M(39) ); ++ R( a, b, c, d, e, F3, K3, M(40) ); ++ R( e, a, b, c, d, F3, K3, M(41) ); ++ R( d, e, a, b, c, F3, K3, M(42) ); ++ R( c, d, e, a, b, F3, K3, M(43) ); ++ R( b, c, d, e, a, F3, K3, M(44) ); ++ R( a, b, c, d, e, F3, K3, M(45) ); ++ R( e, a, b, c, d, F3, K3, M(46) ); ++ R( d, e, a, b, c, F3, K3, M(47) ); ++ R( c, d, e, a, b, F3, K3, M(48) ); ++ R( b, c, d, e, a, F3, K3, M(49) ); ++ R( a, b, c, d, e, F3, K3, M(50) ); ++ R( e, a, b, c, d, F3, K3, M(51) ); ++ R( d, e, a, b, c, F3, K3, M(52) ); ++ R( c, d, e, a, b, F3, K3, M(53) ); ++ R( b, c, d, e, a, F3, K3, M(54) ); ++ R( a, b, c, d, e, F3, K3, M(55) ); ++ R( e, a, b, c, d, F3, K3, M(56) ); ++ R( d, e, a, b, c, F3, K3, M(57) ); ++ R( c, d, e, a, b, F3, K3, M(58) ); ++ R( b, c, d, e, a, F3, K3, M(59) ); ++ R( a, b, c, d, e, F4, K4, M(60) ); ++ R( e, a, b, c, d, F4, K4, M(61) ); ++ R( d, e, a, b, c, F4, K4, M(62) ); ++ R( c, d, e, a, b, F4, K4, M(63) ); ++ R( b, c, d, e, a, F4, K4, M(64) ); ++ R( a, b, c, d, e, F4, K4, M(65) ); ++ R( e, a, b, c, d, F4, K4, M(66) ); ++ R( d, e, a, b, c, F4, K4, M(67) ); ++ R( c, d, e, a, b, F4, K4, M(68) ); ++ R( b, c, d, e, a, F4, K4, M(69) ); ++ R( a, b, c, d, e, F4, K4, M(70) ); ++ R( e, a, b, c, d, F4, K4, M(71) ); ++ R( d, e, a, b, c, F4, K4, M(72) ); ++ R( c, d, e, a, b, F4, K4, M(73) ); ++ R( b, c, d, e, a, F4, K4, M(74) ); ++ R( a, b, c, d, e, F4, K4, M(75) ); ++ R( e, a, b, c, d, F4, K4, M(76) ); ++ R( d, e, a, b, c, F4, K4, M(77) ); ++ R( c, d, e, a, b, F4, K4, M(78) ); ++ R( b, c, d, e, a, F4, K4, M(79) ); ++ ++ a = ctx->A += a; ++ b = ctx->B += b; ++ c = ctx->C += c; ++ d = ctx->D += d; ++ e = ctx->E += e; ++ } ++} +diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/mdadm/sha1.h busybox-1.7.4+gentoo+mdadm/mdadm/sha1.h +--- busybox-1.7.4+gentoo/mdadm/sha1.h 1969-12-31 16:00:00.000000000 -0800 ++++ busybox-1.7.4+gentoo+mdadm/mdadm/sha1.h 2008-03-11 10:31:00.000000000 -0700 +@@ -0,0 +1,87 @@ ++/* Declarations of functions and data types used for SHA1 sum ++ library functions. ++ Copyright (C) 2000, 2001, 2003, 2005 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms of the GNU General Public License as published by the ++ Free Software Foundation; either version 2, or (at your option) any ++ later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software Foundation, ++ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ ++ ++#ifndef SHA1_H ++# define SHA1_H 1 ++ ++# include ++# include "md5.h" ++ ++/* Structure to save state of computation between the single steps. */ ++struct sha1_ctx ++{ ++ md5_uint32 A; ++ md5_uint32 B; ++ md5_uint32 C; ++ md5_uint32 D; ++ md5_uint32 E; ++ ++ md5_uint32 total[2]; ++ md5_uint32 buflen; ++ char buffer[128] __attribute__ ((__aligned__ (__alignof__ (md5_uint32)))); ++}; ++ ++ ++/* Initialize structure containing state of computation. */ ++extern void sha1_init_ctx (struct sha1_ctx *ctx); ++ ++/* Starting with the result of former calls of this function (or the ++ initialization function update the context for the next LEN bytes ++ starting at BUFFER. ++ It is necessary that LEN is a multiple of 64!!! */ ++extern void sha1_process_block (const void *buffer, size_t len, ++ struct sha1_ctx *ctx); ++ ++/* Starting with the result of former calls of this function (or the ++ initialization function update the context for the next LEN bytes ++ starting at BUFFER. ++ It is NOT required that LEN is a multiple of 64. */ ++extern void sha1_process_bytes (const void *buffer, size_t len, ++ struct sha1_ctx *ctx); ++ ++/* Process the remaining bytes in the buffer and put result from CTX ++ in first 20 bytes following RESBUF. The result is always in little ++ endian byte order, so that a byte-wise output yields to the wanted ++ ASCII representation of the message digest. ++ ++ IMPORTANT: On some systems it is required that RESBUF be correctly ++ aligned for a 32 bits value. */ ++extern void *sha1_finish_ctx (struct sha1_ctx *ctx, void *resbuf); ++ ++ ++/* Put result from CTX in first 20 bytes following RESBUF. The result is ++ always in little endian byte order, so that a byte-wise output yields ++ to the wanted ASCII representation of the message digest. ++ ++ IMPORTANT: On some systems it is required that RESBUF is correctly ++ aligned for a 32 bits value. */ ++extern void *sha1_read_ctx (const struct sha1_ctx *ctx, void *resbuf); ++ ++ ++/* Compute SHA1 message digest for bytes read from STREAM. The ++ resulting message digest number will be written into the 20 bytes ++ beginning at RESBLOCK. */ ++extern int sha1_stream (FILE *stream, void *resblock); ++ ++/* Compute SHA1 message digest for LEN bytes beginning at BUFFER. The ++ result is always in little endian byte order, so that a byte-wise ++ output yields to the wanted ASCII representation of the message ++ digest. */ ++extern void *sha1_buffer (const char *buffer, size_t len, void *resblock); ++ ++#endif +diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/mdadm/super0.c busybox-1.7.4+gentoo+mdadm/mdadm/super0.c +--- busybox-1.7.4+gentoo/mdadm/super0.c 1969-12-31 16:00:00.000000000 -0800 ++++ busybox-1.7.4+gentoo+mdadm/mdadm/super0.c 2008-03-11 10:31:00.000000000 -0700 +@@ -0,0 +1,562 @@ ++/* ++ * mdadm - manage Linux "md" devices aka RAID arrays. ++ * ++ * Copyright (C) 2001-2006 Neil Brown ++ * ++ * ++ * 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: ++ * 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<disks[i].raid_disk < info->array.raid_disks) && ++ (sb->disks[i].state & (1<disks[i].state & (1<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<nr_disks++; ++ if (state & (1<active_disks++; ++ if (state & (1<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<disks[d].state & ~(1<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<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<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<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<magic) != BITMAP_MAGIC || ++ memcmp(bsb->uuid, uuid, 16) != 0) ++ goto no_bitmap; ++ return 0; ++ ++ no_bitmap: ++ super->state &= ~(1<ss = &super0; ++ st->minor_version = 90; ++ st->max_devs = MD_SB_DISKS; ++ if (strcmp(arg, "0") == 0 || ++ strcmp(arg, "0.90") == 0 || ++ strcmp(arg, "default") == 0 ++ ) ++ return st; ++ ++ st->minor_version = 9; /* flag for 'byte-swapped' */ ++ if (strcmp(arg, "0.swap")==0) ++ return st; ++ ++ free(st); ++ return NULL; ++} ++ ++void locate_bitmap0(struct supertype *st, int fd, void *sbv) ++{ ++ unsigned long long dsize; ++ unsigned long long offset; ++ ++ if (!get_dev_size(fd, NULL, &dsize)) ++ return; ++ ++ if (dsize < MD_RESERVED_SECTORS*512 * 2) ++ return; ++ ++ offset = MD_NEW_SIZE_SECTORS(dsize>>9); ++ ++ offset *= 512; ++ ++ offset += MD_SB_BYTES; ++ ++ lseek64(fd, offset, 0); ++} ++ ++struct superswitch super0 = { ++ .examine_super = NULL, ++ .brief_examine_super = brief_examine_super0, ++ .detail_super = NULL, ++ .brief_detail_super = NULL, ++ .export_super = NULL, ++ .match_home = match_home0, ++ .uuid_from_super = uuid_from_super0, ++ .getinfo_super = getinfo_super0, ++ .update_super = update_super0, ++ .init_super = NULL, ++ .add_to_super = NULL, ++ .store_super = store_super0, ++ .write_init_super = NULL, ++ .compare_super = compare_super0, ++ .load_super = load_super0, ++ .match_metadata_desc = match_metadata_desc0, ++ .avail_size = NULL, ++ .add_internal_bitmap = NULL, ++ .locate_bitmap = locate_bitmap0, ++ .write_bitmap = NULL, ++ .major = 0, ++ .swapuuid = 0, ++}; +diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/mdadm/super1.c busybox-1.7.4+gentoo+mdadm/mdadm/super1.c +--- busybox-1.7.4+gentoo/mdadm/super1.c 1969-12-31 16:00:00.000000000 -0800 ++++ busybox-1.7.4+gentoo+mdadm/mdadm/super1.c 2008-03-11 10:31:00.000000000 -0700 +@@ -0,0 +1,731 @@ ++/* ++ * mdadm - manage Linux "md" devices aka RAID arrays. ++ * ++ * Copyright (C) 2001-2006 Neil Brown ++ * ++ * ++ * 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: ++ * Paper: Neil Brown ++ * School of Computer Science and Engineering ++ * The University of New South Wales ++ * Sydney, 2052 ++ * Australia ++ */ ++ ++#include "mdadm.h" ++/* ++ * The version-1 superblock : ++ * All numeric fields are little-endian. ++ * ++ * total size: 256 bytes plus 2 per device. ++ * 1K allows 384 devices. ++ */ ++struct mdp_superblock_1 { ++ /* constant array information - 128 bytes */ ++ __u32 magic; /* MD_SB_MAGIC: 0xa92b4efc - little endian */ ++ __u32 major_version; /* 1 */ ++ __u32 feature_map; /* 0 for now */ ++ __u32 pad0; /* always set to 0 when writing */ ++ ++ __u8 set_uuid[16]; /* user-space generated. */ ++ char set_name[32]; /* set and interpreted by user-space */ ++ ++ __u64 ctime; /* lo 40 bits are seconds, top 24 are microseconds or 0*/ ++ __u32 level; /* -4 (multipath), -1 (linear), 0,1,4,5 */ ++ __u32 layout; /* only for raid5 currently */ ++ __u64 size; /* used size of component devices, in 512byte sectors */ ++ ++ __u32 chunksize; /* in 512byte sectors */ ++ __u32 raid_disks; ++ __u32 bitmap_offset; /* sectors after start of superblock that bitmap starts ++ * NOTE: signed, so bitmap can be before superblock ++ * only meaningful of feature_map[0] is set. ++ */ ++ ++ /* These are only valid with feature bit '4' */ ++ __u32 new_level; /* new level we are reshaping to */ ++ __u64 reshape_position; /* next address in array-space for reshape */ ++ __u32 delta_disks; /* change in number of raid_disks */ ++ __u32 new_layout; /* new layout */ ++ __u32 new_chunk; /* new chunk size (bytes) */ ++ __u8 pad1[128-124]; /* set to 0 when written */ ++ ++ /* constant this-device information - 64 bytes */ ++ __u64 data_offset; /* sector start of data, often 0 */ ++ __u64 data_size; /* sectors in this device that can be used for data */ ++ __u64 super_offset; /* sector start of this superblock */ ++ __u64 recovery_offset;/* sectors before this offset (from data_offset) have been recovered */ ++ __u32 dev_number; /* permanent identifier of this device - not role in raid */ ++ __u32 cnt_corrected_read; /* number of read errors that were corrected by re-writing */ ++ __u8 device_uuid[16]; /* user-space setable, ignored by kernel */ ++ __u8 devflags; /* per-device flags. Only one defined...*/ ++#define WriteMostly1 1 /* mask for writemostly flag in above */ ++ __u8 pad2[64-57]; /* set to 0 when writing */ ++ ++ /* array state information - 64 bytes */ ++ __u64 utime; /* 40 bits second, 24 btes microseconds */ ++ __u64 events; /* incremented when superblock updated */ ++ __u64 resync_offset; /* data before this offset (from data_offset) known to be in sync */ ++ __u32 sb_csum; /* checksum upto devs[max_dev] */ ++ __u32 max_dev; /* size of devs[] array to consider */ ++ __u8 pad3[64-32]; /* set to 0 when writing */ ++ ++ /* device state information. Indexed by dev_number. ++ * 2 bytes per device ++ * Note there are no per-device state flags. State information is rolled ++ * into the 'roles' value. If a device is spare or faulty, then it doesn't ++ * have a meaningful role. ++ */ ++ __u16 dev_roles[0]; /* role in array, or 0xffff for a spare, or 0xfffe for faulty */ ++}; ++ ++struct misc_dev_info { ++ __u64 device_size; ++}; ++ ++/* feature_map bits */ ++#define MD_FEATURE_BITMAP_OFFSET 1 ++#define MD_FEATURE_RECOVERY_OFFSET 2 /* recovery_offset is present and ++ * must be honoured ++ */ ++#define MD_FEATURE_RESHAPE_ACTIVE 4 ++ ++#define MD_FEATURE_ALL (1|2|4) ++ ++#ifndef offsetof ++#define offsetof(t,f) ((size_t)&(((t*)0)->f)) ++#endif ++static unsigned int calc_sb_1_csum(struct mdp_superblock_1 * sb) ++{ ++ unsigned int disk_csum, csum; ++ unsigned long long newcsum; ++ int size = sizeof(*sb) + __le32_to_cpu(sb->max_dev)*2; ++ unsigned int *isuper = (unsigned int*)sb; ++ int i; ++ ++/* make sure I can count... */ ++ if (offsetof(struct mdp_superblock_1,data_offset) != 128 || ++ offsetof(struct mdp_superblock_1, utime) != 192 || ++ sizeof(struct mdp_superblock_1) != 256) { ++ fprintf(stderr, "WARNING - superblock isn't sized correctly\n"); ++ } ++ ++ disk_csum = sb->sb_csum; ++ sb->sb_csum = 0; ++ newcsum = 0; ++ for (i=0; size>=4; size -= 4 ) { ++ newcsum += __le32_to_cpu(*isuper); ++ isuper++; ++ } ++ ++ if (size == 2) ++ newcsum += __le16_to_cpu(*(unsigned short*) isuper); ++ ++ csum = (newcsum & 0xffffffff) + (newcsum >> 32); ++ sb->sb_csum = disk_csum; ++ return __cpu_to_le32(csum); ++} ++ ++static void brief_examine_super1(void *sbv) ++{ ++ struct mdp_superblock_1 *sb = sbv; ++ int i; ++ unsigned long long sb_offset; ++ char *nm; ++ char *c=map_num(pers, __le32_to_cpu(sb->level)); ++ ++ nm = strchr(sb->set_name, ':'); ++ if (nm) ++ nm++; ++ else if (sb->set_name[0]) ++ nm = sb->set_name; ++ else ++ nm = "??"; ++ ++ printf("ARRAY /dev/md%s level=%s ", nm, c?c:"-unknown-"); ++ sb_offset = __le64_to_cpu(sb->super_offset); ++ if (sb_offset <= 4) ++ printf("metadata=1.1 "); ++ else if (sb_offset <= 8) ++ printf("metadata=1.2 "); ++ else ++ printf("metadata=1.0 "); ++ printf("num-devices=%d UUID=", __le32_to_cpu(sb->raid_disks)); ++ for (i=0; i<16; i++) { ++ if ((i&3)==0 && i != 0) printf(":"); ++ printf("%02x", sb->set_uuid[i]); ++ } ++ if (sb->set_name[0]) ++ printf(" name=%.32s", sb->set_name); ++ printf("\n"); ++} ++ ++static int match_home1(void *sbv, char *homehost) ++{ ++ struct mdp_superblock_1 *sb = sbv; ++ int l = homehost ? strlen(homehost) : 0; ++ ++ return (l > 0 && l < 32 && ++ sb->set_name[l] == ':' && ++ strncmp(sb->set_name, homehost, l) == 0); ++} ++ ++static void uuid_from_super1(int uuid[4], void * sbv) ++{ ++ struct mdp_superblock_1 *super = sbv; ++ char *cuuid = (char*)uuid; ++ int i; ++ for (i=0; i<16; i++) ++ cuuid[i] = super->set_uuid[i]; ++} ++ ++static void getinfo_super1(struct mdinfo *info, void *sbv) ++{ ++ struct mdp_superblock_1 *sb = sbv; ++ int working = 0; ++ int i; ++ int role; ++ ++ info->array.major_version = 1; ++ info->array.minor_version = __le32_to_cpu(sb->feature_map); ++ info->array.patch_version = 0; ++ info->array.raid_disks = __le32_to_cpu(sb->raid_disks); ++ info->array.level = __le32_to_cpu(sb->level); ++ info->array.layout = __le32_to_cpu(sb->layout); ++ info->array.md_minor = -1; ++ info->array.ctime = __le64_to_cpu(sb->ctime); ++ info->array.utime = __le64_to_cpu(sb->utime); ++ info->array.chunk_size = __le32_to_cpu(sb->chunksize)*512; ++ info->array.state = ++ (__le64_to_cpu(sb->resync_offset) >= __le64_to_cpu(sb->size)) ++ ? 1 : 0; ++ ++ info->data_offset = __le64_to_cpu(sb->data_offset); ++ info->component_size = __le64_to_cpu(sb->size); ++ ++ info->disk.major = 0; ++ info->disk.minor = 0; ++ info->disk.number = __le32_to_cpu(sb->dev_number); ++ if (__le32_to_cpu(sb->dev_number) >= __le32_to_cpu(sb->max_dev) || ++ __le32_to_cpu(sb->max_dev) > 512) ++ role = 0xfffe; ++ else ++ role = __le16_to_cpu(sb->dev_roles[__le32_to_cpu(sb->dev_number)]); ++ ++ info->disk.raid_disk = -1; ++ switch(role) { ++ case 0xFFFF: ++ info->disk.state = 2; /* spare: ACTIVE, not sync, not faulty */ ++ break; ++ case 0xFFFE: ++ info->disk.state = 1; /* faulty */ ++ break; ++ default: ++ info->disk.state = 6; /* active and in sync */ ++ info->disk.raid_disk = role; ++ } ++ info->events = __le64_to_cpu(sb->events); ++ ++ memcpy(info->uuid, sb->set_uuid, 16); ++ ++ strncpy(info->name, sb->set_name, 32); ++ info->name[32] = 0; ++ ++ if (sb->feature_map & __le32_to_cpu(MD_FEATURE_RESHAPE_ACTIVE)) { ++ info->reshape_active = 1; ++ info->reshape_progress = __le64_to_cpu(sb->reshape_position); ++ info->new_level = __le32_to_cpu(sb->new_level); ++ info->delta_disks = __le32_to_cpu(sb->delta_disks); ++ info->new_layout = __le32_to_cpu(sb->new_layout); ++ info->new_chunk = __le32_to_cpu(sb->new_chunk)<<9; ++ } else ++ info->reshape_active = 0; ++ ++ for (i=0; i< __le32_to_cpu(sb->max_dev); i++) { ++ role = __le16_to_cpu(sb->dev_roles[i]); ++ if (/*role == 0xFFFF || */role < info->array.raid_disks) ++ working++; ++ } ++ ++ info->array.working_disks = working; ++} ++ ++static int update_super1(struct mdinfo *info, void *sbv, char *update, ++ char *devname, int verbose, ++ int uuid_set, char *homehost) ++{ ++ /* NOTE: for 'assemble' and 'force' we need to return non-zero if any change was made. ++ * For others, the return value is ignored. ++ */ ++ int rv = 0; ++ struct mdp_superblock_1 *sb = sbv; ++ ++ if (strcmp(update, "force-one")==0) { ++ /* Not enough devices for a working array, ++ * so bring this one up-to-date ++ */ ++ if (sb->events != __cpu_to_le64(info->events)) ++ rv = 1; ++ sb->events = __cpu_to_le64(info->events); ++ } ++ if (strcmp(update, "force-array")==0) { ++ /* Degraded array and 'force' requests to ++ * maybe need to mark it 'clean'. ++ */ ++ switch(__le32_to_cpu(sb->level)) { ++ case 5: case 4: case 6: ++ /* need to force clean */ ++ if (sb->resync_offset != ~0ULL) ++ rv = 1; ++ sb->resync_offset = ~0ULL; ++ } ++ } ++ if (strcmp(update, "assemble")==0) { ++ int d = info->disk.number; ++ int want; ++ if (info->disk.state == 6) ++ want = __cpu_to_le32(info->disk.raid_disk); ++ else ++ want = 0xFFFF; ++ if (sb->dev_roles[d] != want) { ++ sb->dev_roles[d] = want; ++ rv = 1; ++ } ++ } ++ if (strcmp(update, "linear-grow-new") == 0) { ++ int i; ++ int rfd; ++ int max = __le32_to_cpu(sb->max_dev); ++ ++ for (i=0 ; i < max ; i++) ++ if (__le16_to_cpu(sb->dev_roles[i]) >= 0xfffe) ++ break; ++ sb->dev_number = __cpu_to_le32(i); ++ info->disk.number = i; ++ if (max >= __le32_to_cpu(sb->max_dev)) ++ sb->max_dev = __cpu_to_le32(max+1); ++ ++ if ((rfd = open("/dev/urandom", O_RDONLY)) < 0 || ++ read(rfd, sb->device_uuid, 16) != 16) { ++ *(__u32*)(sb->device_uuid) = random(); ++ *(__u32*)(sb->device_uuid+4) = random(); ++ *(__u32*)(sb->device_uuid+8) = random(); ++ *(__u32*)(sb->device_uuid+12) = random(); ++ } ++ ++ sb->dev_roles[i] = ++ __cpu_to_le16(info->disk.raid_disk); ++ } ++ if (strcmp(update, "linear-grow-update") == 0) { ++ sb->raid_disks = __cpu_to_le32(info->array.raid_disks); ++ sb->dev_roles[info->disk.number] = ++ __cpu_to_le16(info->disk.raid_disk); ++ } ++ if (strcmp(update, "resync") == 0) { ++ /* make sure resync happens */ ++ sb->resync_offset = 0ULL; ++ } ++ if (strcmp(update, "uuid") == 0) { ++ copy_uuid(sb->set_uuid, info->uuid, super1.swapuuid); ++ ++ if (__le32_to_cpu(sb->feature_map)&MD_FEATURE_BITMAP_OFFSET) { ++ struct bitmap_super_s *bm; ++ bm = (struct bitmap_super_s*)(sbv+1024); ++ memcpy(bm->uuid, sb->set_uuid, 16); ++ } ++ } ++ if (strcmp(update, "homehost") == 0 && ++ homehost) { ++ char *c; ++ update = "name"; ++ c = strchr(sb->set_name, ':'); ++ if (c) ++ strncpy(info->name, c+1, 31 - (c-sb->set_name)); ++ else ++ strncpy(info->name, sb->set_name, 32); ++ info->name[32] = 0; ++ } ++ if (strcmp(update, "name") == 0) { ++ if (info->name[0] == 0) ++ sprintf(info->name, "%d", info->array.md_minor); ++ memset(sb->set_name, 0, sizeof(sb->set_name)); ++ if (homehost && ++ strchr(info->name, ':') == NULL && ++ strlen(homehost)+1+strlen(info->name) < 32) { ++ strcpy(sb->set_name, homehost); ++ strcat(sb->set_name, ":"); ++ strcat(sb->set_name, info->name); ++ } else ++ strcpy(sb->set_name, info->name); ++ } ++ if (strcmp(update, "devicesize") == 0 && ++ __le64_to_cpu(sb->super_offset) < ++ __le64_to_cpu(sb->data_offset)) { ++ /* set data_size to device size less data_offset */ ++ struct misc_dev_info *misc = (struct misc_dev_info*) ++ (sbv + 1024 + sizeof(struct bitmap_super_s)); ++ printf("Size was %llu\n", (unsigned long long) ++ __le64_to_cpu(sb->data_size)); ++ sb->data_size = __cpu_to_le64( ++ misc->device_size - __le64_to_cpu(sb->data_offset)); ++ printf("Size is %llu\n", (unsigned long long) ++ __le64_to_cpu(sb->data_size)); ++ } ++ if (strcmp(update, "_reshape_progress")==0) ++ sb->reshape_position = __cpu_to_le64(info->reshape_progress); ++ ++ sb->sb_csum = calc_sb_1_csum(sb); ++ return rv; ++} ++ ++static void locate_bitmap1(struct supertype *st, int fd, void *sbv); ++ ++static int store_super1(struct supertype *st, int fd, void *sbv) ++{ ++ struct mdp_superblock_1 *sb = sbv; ++ unsigned long long sb_offset; ++ int sbsize; ++ unsigned long long dsize; ++ ++ if (!get_dev_size(fd, NULL, &dsize)) ++ return 1; ++ ++ dsize >>= 9; ++ ++ if (dsize < 24) ++ return 2; ++ ++ /* ++ * Calculate the position of the superblock. ++ * It is always aligned to a 4K boundary and ++ * depending on minor_version, it can be: ++ * 0: At least 8K, but less than 12K, from end of device ++ * 1: At start of device ++ * 2: 4K from start of device. ++ */ ++ switch(st->minor_version) { ++ case 0: ++ sb_offset = dsize; ++ sb_offset -= 8*2; ++ sb_offset &= ~(4*2-1); ++ break; ++ case 1: ++ sb_offset = 0; ++ break; ++ case 2: ++ sb_offset = 4*2; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ ++ ++ if (sb_offset != __le64_to_cpu(sb->super_offset) && ++ 0 != __le64_to_cpu(sb->super_offset) ++ ) { ++ fprintf(stderr, Name ": internal error - sb_offset is wrong\n"); ++ abort(); ++ } ++ ++ if (lseek64(fd, sb_offset << 9, 0)< 0LL) ++ return 3; ++ ++ sbsize = sizeof(*sb) + 2 * __le32_to_cpu(sb->max_dev); ++ ++ if (write(fd, sb, sbsize) != sbsize) ++ return 4; ++ ++ if (sb->feature_map & __cpu_to_le32(MD_FEATURE_BITMAP_OFFSET)) { ++ struct bitmap_super_s *bm = (struct bitmap_super_s*) ++ (((char*)sb)+1024); ++ if (__le32_to_cpu(bm->magic) == BITMAP_MAGIC) { ++ locate_bitmap1(st, fd, sbv); ++ if (write(fd, bm, sizeof(*bm)) != sizeof(*bm)) ++ return 5; ++ } ++ } ++ fsync(fd); ++ return 0; ++} ++ ++static int load_super1(struct supertype *st, int fd, void **sbp, char *devname); ++ ++static int compare_super1(void **firstp, void *secondv) ++{ ++ /* ++ * return: ++ * 0 same, or first was empty, and second was copied ++ * 1 second had wrong number ++ * 2 wrong uuid ++ * 3 wrong other info ++ */ ++ struct mdp_superblock_1 *first = *firstp; ++ struct mdp_superblock_1 *second = secondv; ++ ++ if (second->magic != __cpu_to_le32(MD_SB_MAGIC)) ++ return 1; ++ if (second->major_version != __cpu_to_le32(1)) ++ return 1; ++ ++ if (!first) { ++ first = malloc(1024+sizeof(bitmap_super_t) + ++ sizeof(struct misc_dev_info)); ++ memcpy(first, second, 1024+sizeof(bitmap_super_t) + ++ sizeof(struct misc_dev_info)); ++ *firstp = first; ++ return 0; ++ } ++ if (memcmp(first->set_uuid, second->set_uuid, 16)!= 0) ++ return 2; ++ ++ if (first->ctime != second->ctime || ++ first->level != second->level || ++ first->layout != second->layout || ++ first->size != second->size || ++ first->chunksize != second->chunksize || ++ first->raid_disks != second->raid_disks) ++ return 3; ++ return 0; ++} ++ ++static int load_super1(struct supertype *st, int fd, void **sbp, char *devname) ++{ ++ unsigned long long dsize; ++ unsigned long long sb_offset; ++ struct mdp_superblock_1 *super; ++ int uuid[4]; ++ struct bitmap_super_s *bsb; ++ struct misc_dev_info *misc; ++ ++ ++ if (st->ss == NULL) { ++ int bestvers = -1; ++ __u64 bestctime = 0; ++ /* guess... choose latest ctime */ ++ st->ss = &super1; ++ for (st->minor_version = 0; st->minor_version <= 2 ; st->minor_version++) { ++ switch(load_super1(st, fd, sbp, devname)) { ++ case 0: super = *sbp; ++ if (bestvers == -1 || ++ bestctime < __le64_to_cpu(super->ctime)) { ++ bestvers = st->minor_version; ++ bestctime = __le64_to_cpu(super->ctime); ++ } ++ free(super); ++ *sbp = NULL; ++ break; ++ case 1: st->ss = NULL; return 1; /*bad device */ ++ case 2: break; /* bad, try next */ ++ } ++ } ++ if (bestvers != -1) { ++ int rv; ++ st->minor_version = bestvers; ++ st->ss = &super1; ++ st->max_devs = 384; ++ rv = load_super1(st, fd, sbp, devname); ++ if (rv) st->ss = NULL; ++ return rv; ++ } ++ st->ss = NULL; ++ return 2; ++ } ++ if (!get_dev_size(fd, devname, &dsize)) ++ return 1; ++ dsize >>= 9; ++ ++ if (dsize < 24) { ++ if (devname) ++ fprintf(stderr, Name ": %s is too small for md: size is %llu sectors.\n", ++ devname, dsize); ++ return 1; ++ } ++ ++ /* ++ * Calculate the position of the superblock. ++ * It is always aligned to a 4K boundary and ++ * depending on minor_version, it can be: ++ * 0: At least 8K, but less than 12K, from end of device ++ * 1: At start of device ++ * 2: 4K from start of device. ++ */ ++ switch(st->minor_version) { ++ case 0: ++ sb_offset = dsize; ++ sb_offset -= 8*2; ++ sb_offset &= ~(4*2-1); ++ break; ++ case 1: ++ sb_offset = 0; ++ break; ++ case 2: ++ sb_offset = 4*2; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ ioctl(fd, BLKFLSBUF, 0); /* make sure we read current data */ ++ ++ ++ if (lseek64(fd, sb_offset << 9, 0)< 0LL) { ++ if (devname) ++ fprintf(stderr, Name ": Cannot seek to superblock on %s: %s\n", ++ devname, strerror(errno)); ++ return 1; ++ } ++ ++ super = malloc(1024 + sizeof(bitmap_super_t) + ++ sizeof(struct misc_dev_info)); ++ ++ if (read(fd, super, 1024) != 1024) { ++ if (devname) ++ fprintf(stderr, Name ": Cannot read superblock on %s\n", ++ devname); ++ free(super); ++ return 1; ++ } ++ ++ if (__le32_to_cpu(super->magic) != MD_SB_MAGIC) { ++ if (devname) ++ fprintf(stderr, Name ": No super block found on %s (Expected magic %08x, got %08x)\n", ++ devname, MD_SB_MAGIC, __le32_to_cpu(super->magic)); ++ free(super); ++ return 2; ++ } ++ ++ if (__le32_to_cpu(super->major_version) != 1) { ++ if (devname) ++ fprintf(stderr, Name ": Cannot interpret superblock on %s - version is %d\n", ++ devname, __le32_to_cpu(super->major_version)); ++ free(super); ++ return 2; ++ } ++ if (__le64_to_cpu(super->super_offset) != sb_offset) { ++ if (devname) ++ fprintf(stderr, Name ": No superblock found on %s (super_offset is wrong)\n", ++ devname); ++ free(super); ++ return 2; ++ } ++ *sbp = super; ++ ++ bsb = (struct bitmap_super_s *)(((char*)super)+1024); ++ ++ misc = (struct misc_dev_info*) (bsb+1); ++ misc->device_size = dsize; ++ ++ /* Now check on the bitmap superblock */ ++ if ((__le32_to_cpu(super->feature_map)&MD_FEATURE_BITMAP_OFFSET) == 0) ++ return 0; ++ /* Read the bitmap superblock and make sure it looks ++ * valid. If it doesn't clear the bit. An --assemble --force ++ * should get that written out. ++ */ ++ locate_bitmap1(st, fd, super); ++ if (read(fd, ((char*)super)+1024, sizeof(struct bitmap_super_s)) ++ != sizeof(struct bitmap_super_s)) ++ goto no_bitmap; ++ ++ uuid_from_super1(uuid, super); ++ if (__le32_to_cpu(bsb->magic) != BITMAP_MAGIC || ++ memcmp(bsb->uuid, uuid, 16) != 0) ++ goto no_bitmap; ++ return 0; ++ ++ no_bitmap: ++ super->feature_map = __cpu_to_le32(__le32_to_cpu(super->feature_map) & ~1); ++ return 0; ++} ++ ++ ++static struct supertype *match_metadata_desc1(char *arg) ++{ ++ struct supertype *st = malloc(sizeof(*st)); ++ if (!st) return st; ++ ++ st->ss = &super1; ++ st->max_devs = 384; ++ if (strcmp(arg, "1") == 0 || ++ strcmp(arg, "1.0") == 0 || ++ strcmp(arg, "default/large") == 0) { ++ st->minor_version = 0; ++ return st; ++ } ++ if (strcmp(arg, "1.1") == 0) { ++ st->minor_version = 1; ++ return st; ++ } ++ if (strcmp(arg, "1.2") == 0) { ++ st->minor_version = 2; ++ return st; ++ } ++ ++ free(st); ++ return NULL; ++} ++ ++static void locate_bitmap1(struct supertype *st, int fd, void *sbv) ++{ ++ unsigned long long offset; ++ struct mdp_superblock_1 *sb; ++ int mustfree = 0; ++ ++ if (!sbv) { ++ if (st->ss->load_super(st, fd, &sbv, NULL)) ++ return; /* no error I hope... */ ++ mustfree = 1; ++ } ++ sb = sbv; ++ ++ offset = __le64_to_cpu(sb->super_offset); ++ offset += (int32_t) __le32_to_cpu(sb->bitmap_offset); ++ if (mustfree) ++ free(sb); ++ lseek64(fd, offset<<9, 0); ++} ++ ++struct superswitch super1 = { ++ .examine_super = NULL, ++ .brief_examine_super = brief_examine_super1, ++ .detail_super = NULL, ++ .brief_detail_super = NULL, ++ .export_super = NULL, ++ .match_home = match_home1, ++ .uuid_from_super = uuid_from_super1, ++ .getinfo_super = getinfo_super1, ++ .update_super = update_super1, ++ .init_super = NULL, ++ .add_to_super = NULL, ++ .store_super = store_super1, ++ .write_init_super = NULL, ++ .compare_super = compare_super1, ++ .load_super = load_super1, ++ .match_metadata_desc = match_metadata_desc1, ++ .avail_size = NULL, ++ .add_internal_bitmap = NULL, ++ .locate_bitmap = locate_bitmap1, ++ .write_bitmap = NULL, ++ .major = 1, ++#if __BYTE_ORDER == BIG_ENDIAN ++ .swapuuid = 0, ++#else ++ .swapuuid = 1, ++#endif ++}; +diff -Nuar --exclude '*.orig' busybox-1.7.4+gentoo/mdadm/util.c busybox-1.7.4+gentoo+mdadm/mdadm/util.c +--- busybox-1.7.4+gentoo/mdadm/util.c 1969-12-31 16:00:00.000000000 -0800 ++++ busybox-1.7.4+gentoo+mdadm/mdadm/util.c 2008-03-11 10:31:00.000000000 -0700 +@@ -0,0 +1,652 @@ ++/* ++ * mdadm - manage Linux "md" devices aka RAID arrays. ++ * ++ * Copyright (C) 2001-2006 Neil Brown ++ * ++ * ++ * 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: ++ * 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 ++#include ++ ++/* ++ * 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 :. 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>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.7.4/1.7.4-mdstart.diff b/patches/busybox/1.7.4/1.7.4-mdstart.diff new file mode 100644 index 0000000..c13670d --- /dev/null +++ b/patches/busybox/1.7.4/1.7.4-mdstart.diff @@ -0,0 +1,120 @@ +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 + +diff -Nuar --exclude '*.orig' busybox-1.7.4/include/applets.h busybox-1.7.4+gentoo/include/applets.h +--- busybox-1.7.4/include/applets.h 2007-09-03 04:48:46.000000000 -0700 ++++ busybox-1.7.4+gentoo/include/applets.h 2008-03-11 10:25:43.000000000 -0700 +@@ -222,6 +222,7 @@ + USE_MATCHPATHCON(APPLET(matchpathcon, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)) + USE_MD5SUM(APPLET_ODDNAME(md5sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_NEVER, md5sum)) + USE_MDEV(APPLET(mdev, _BB_DIR_SBIN, _BB_SUID_NEVER)) ++USE_MDSTART(APPLET(mdstart, _BB_DIR_SBIN, _BB_SUID_NEVER)) + USE_MESG(APPLET(mesg, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) + USE_MKDIR(APPLET_NOFORK(mkdir, mkdir, _BB_DIR_BIN, _BB_SUID_NEVER, mkdir)) + //USE_MKE2FS(APPLET(mke2fs, _BB_DIR_SBIN, _BB_SUID_NEVER)) +diff -Nuar --exclude '*.orig' busybox-1.7.4/include/usage.h busybox-1.7.4+gentoo/include/usage.h +--- busybox-1.7.4/include/usage.h 2007-09-03 04:48:46.000000000 -0700 ++++ busybox-1.7.4+gentoo/include/usage.h 2008-03-11 10:19:04.000000000 -0700 +@@ -2072,6 +2072,9 @@ + "the last line match .* to override this.)\n\n" \ + ) + ++#define mdstart_trivial_usage \ ++ "{[PARTITION] MD-NODE}..." ++ + #define mesg_trivial_usage \ + "[y|n]" + #define mesg_full_usage \ +diff -Nuar --exclude '*.orig' busybox-1.7.4/util-linux/Config.in busybox-1.7.4+gentoo/util-linux/Config.in +--- busybox-1.7.4/util-linux/Config.in 2007-09-03 04:48:56.000000000 -0700 ++++ busybox-1.7.4+gentoo/util-linux/Config.in 2008-03-11 10:26:20.000000000 -0700 +@@ -305,6 +305,13 @@ + /lib/firmware/ and if it exists, send it to the kernel for + loading into the hardware. + ++config 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 n +diff -Nuar --exclude '*.orig' busybox-1.7.4/util-linux/Kbuild busybox-1.7.4+gentoo/util-linux/Kbuild +--- busybox-1.7.4/util-linux/Kbuild 2007-09-03 04:48:56.000000000 -0700 ++++ busybox-1.7.4+gentoo/util-linux/Kbuild 2008-03-11 10:28:47.000000000 -0700 +@@ -18,6 +18,7 @@ + lib-$(CONFIG_IPCRM) +=ipcrm.o + lib-$(CONFIG_IPCS) +=ipcs.o + lib-$(CONFIG_LOSETUP) +=losetup.o ++lib-$(CONFIG_MDSTART) +=mdStart.o + lib-$(CONFIG_MDEV) +=mdev.o + lib-$(CONFIG_MKFS_MINIX) +=mkfs_minix.o + lib-$(CONFIG_MKSWAP) +=mkswap.o +diff -Nuar --exclude '*.orig' busybox-1.7.4/util-linux/mdStart.c busybox-1.7.4+gentoo/util-linux/mdStart.c +--- busybox-1.7.4/util-linux/mdStart.c 1969-12-31 16:00:00.000000000 -0800 ++++ busybox-1.7.4+gentoo/util-linux/mdStart.c 2008-03-11 10:19:04.000000000 -0700 +@@ -0,0 +1,59 @@ ++/* ++ * Linux 2.6(+) RAID Autostarter ++ * ++ * Copyright (C) 2005 by Tim Yamin ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++ ++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.7.4/1.7.4-openvt.diff b/patches/busybox/1.7.4/1.7.4-openvt.diff new file mode 100644 index 0000000..aa9e77f --- /dev/null +++ b/patches/busybox/1.7.4/1.7.4-openvt.diff @@ -0,0 +1,20 @@ +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 + +diff -Nuar --exclude '*.orig' busybox-1.7.4/console-tools/openvt.c busybox-1.7.4+gentoo/console-tools/openvt.c +--- busybox-1.7.4/console-tools/openvt.c 2007-09-03 04:48:35.000000000 -0700 ++++ busybox-1.7.4+gentoo/console-tools/openvt.c 2008-03-10 10:00:55.000000000 -0700 +@@ -21,7 +21,7 @@ + bb_show_usage(); + + /* check for illegal vt number: < 1 or > 63 */ +- sprintf(vtname, VC_FORMAT, (int)xatou_range(argv[1], 1, 63)); ++ sprintf(vtname, VC_FORMAT, (int)xatou_range(argv[1], 0, 63)); + + bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv); + /* grab new one */ -- cgit v1.2.3-65-gdbad