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, _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 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/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; +} --- busybox-1.7.4+gentoo/mdadm/Kbuild 2008-03-01 18:44:05.526713152 -0800 +++ busybox-1.7.4+gentoo+mdadm/mdadm/Kbuild 2008-03-11 12:19:18.000000000 -0700 @@ -0,0 +1,9 @@ +# Makefile for busybox +# +# Copyright (C) 1999-2005 by Erik Andersen +# +# Licensed under the GPL v2, see the file LICENSE in this tarball. + +lib-y:= +MDADM-y:= config.o util.o dlink.o sha1.o super0.o super1.o mdexamine.o mdassemble.o +lib-$(CONFIG_MDADM) += mdadm.o $(MDADM-y)