diff options
author | Neil Brown <neilb@suse.de> | 2001-07-26 09:00:09 +0200 |
---|---|---|
committer | Neil Brown <neilb@suse.de> | 2001-07-26 09:00:09 +0200 |
commit | 82b27616de634964db1a71bd5d9813db71e391a1 (patch) | |
tree | 310a2ed60dbb0903c73ba261914da269e9ec9072 | |
parent | mdctl-v0.3 (diff) | |
download | mdadm-82b27616de634964db1a71bd5d9813db71e391a1.tar.xz mdadm-82b27616de634964db1a71bd5d9813db71e391a1.zip |
mdctl-v0.4mdctl-v0.4
-rw-r--r-- | Assemble.c | 97 | ||||
-rw-r--r-- | Build.c | 133 | ||||
-rw-r--r-- | Create.c | 53 | ||||
-rw-r--r-- | Detail.c | 38 | ||||
-rw-r--r-- | Examine.c | 25 | ||||
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | Manage.c | 19 | ||||
-rw-r--r-- | ReadMe.c | 2 | ||||
-rw-r--r-- | TODO | 16 | ||||
-rw-r--r-- | config.c | 289 | ||||
-rw-r--r-- | dlink.c | 76 | ||||
-rw-r--r-- | dlink.h | 25 | ||||
-rw-r--r-- | mdctl.c | 6 | ||||
-rw-r--r-- | mdctl.h | 1 | ||||
-rw-r--r-- | testconfig | 12 | ||||
-rw-r--r-- | testconfig2 | 3 | ||||
-rw-r--r-- | util.c | 95 |
17 files changed, 855 insertions, 39 deletions
@@ -107,7 +107,7 @@ int Assemble(char *mddev, int mdfd, int most_recent = 0; if (!mddev && !scan) { - fputs(Name ": internal error - Assemble called with no devie or scan\n", stderr); + fputs(Name ": internal error - Assemble called with no device or --scan\n", stderr); return 1; } if (!mddev) { @@ -118,7 +118,7 @@ int Assemble(char *mddev, int mdfd, fprintf(stderr, Name ": No devices found in config file\n"); return 1; } - while (device_list) { + for (; device_list; device_list=device_list->next) { if (!uuidset || same_uuid(device_list->uuid,uuid)) { mdfd = open(device_list->devname, O_RDONLY, 0); if (mdfd < 0) { @@ -136,11 +136,10 @@ int Assemble(char *mddev, int mdfd, found++; close(mdfd); } - device_list = device_list->next; } if (found) return 0; - fprintf(stderr,Name ": Did not successful Assemble any devices\n"); + fprintf(stderr,Name ": Did not successfully Assemble any devices\n"); return 1; } @@ -206,6 +205,10 @@ int Assemble(char *mddev, int mdfd, for (i=0; i<MD_SB_DISKS; i++) best[i] = -1; + if (verbose) + fprintf(stderr, Name ": looking for devices for %s\n", + mddev); + while (subdevs || devlist) { char *devname; int this_uuid[4]; @@ -250,6 +253,13 @@ int Assemble(char *mddev, int mdfd, continue; } close(dfd); + uuid_from_super(this_uuid, &super); + if (uuidset && !same_uuid(this_uuid, uuid)) { + if (inargv || verbose) + fprintf(stderr, Name ": %s has wrong uuid.\n", + devname); + continue; + } if (compare_super(&first_super, &super)) { if (inargv || verbose) fprintf(stderr, Name ": superblock on %s doesn't match\n", @@ -341,8 +351,8 @@ int Assemble(char *mddev, int mdfd, devices[j].devname, mddev, strerror(errno)); - } else okcnt--; + } } else if (verbose) fprintf(stderr, Name ": no uptodate device for slot %d of %s\n", i, mddev); @@ -350,17 +360,84 @@ int Assemble(char *mddev, int mdfd, if (runstop == 1 || (runstop == 0 && enough(first_super.level, first_super.raid_disks, okcnt))) { - if (ioctl(mdfd, RUN_ARRAY, NULL)==0) + if (ioctl(mdfd, RUN_ARRAY, NULL)==0) { + fprintf(stderr, Name ": %s has been started with %d drives\n", + mddev, okcnt); return 0; + } fprintf(stderr, Name ": failed to RUN_ARRAY %s: %s\n", mddev, strerror(errno)); return 1; } - if (runstop == -1) + if (runstop == -1) { + fprintf(stderr, Name ": %s assembled from %d drives, but not started.\n", + mddev, okcnt); return 0; - else return 1; - } else { - /* FIXME */ + } + fprintf(stderr, Name ": %s assembled from %d drives - not enough to start it.\n", + mddev, okcnt); return 1; + } else { + /* It maybe just a case of calling START_ARRAY, but it may not.. + * We need to pick a working device, read it's super block, and make + * sure all the device numbers and the minor number are right. + * Then we might need to re-write the super block. + * THEN we call START_ARRAY + * If the md_minor is wrong, wejust give up for now. The alternate is to + * re-write ALL super blocks. + */ + int chosen_drive = -1; + int change = 0; + int dev; + for (i=0; i<first_super.nr_disks; i++) { + if (!devices[i].uptodate) + continue; + if (chosen_drive == -1) { + int fd; + chosen_drive = i; + if (open(devices[i].devname, O_RDONLY)>= 0) { + fprintf(stderr, Name ": Cannot open %s: %s\n", + devices[i].devname, strerror(errno)); + return 1; + } + if (load_super(fd, &super)) { + close(fd); + fprintf(stderr, Name ": RAID superblock has disappeared from %s\n", + devices[i].devname); + return 1; + } + close(fd); + } + if (devices[i].major != super.disks[i].major || + devices[i].minor != super.disks[i].minor) { + change = 1; + super.disks[i].major = devices[i].major; + super.disks[i].minor = devices[i].minor; + } + } + if (change) { + int fd; + super.sb_csum = calc_sb_csum(super); + fd = open(devices[chosen_drive].devname, O_RDWR); + if (fd < 0) { + fprintf(stderr, Name ": Could open %s for write - cannot Assemble array.\n", + devices[chosen_drive].devname); + return 1; + } + if (store_super(fd, &super)) { + close(fd); + fprintf(stderr, Name ": Could not re-write superblock on %s\n", + devices[chosen_drive].devname); + return 1; + } + close(fd); + } + dev = MKDEV(devices[chosen_drive].major, + devices[chosen_drive].minor); + if (ioctl(mdfd, START_ARRAY, dev)) { + fprintf(stderr, Name ": Cannot start array: %s\n", + strerror(errno)); + } + } } @@ -29,8 +29,141 @@ #include "mdctl.h" +#define REGISTER_DEV _IO (MD_MAJOR, 1) +#define START_MD _IO (MD_MAJOR, 2) +#define STOP_MD _IO (MD_MAJOR, 3) + int Build(char *mddev, int mdfd, int chunk, int level, int raiddisks, int subdevs, char *subdev[]) { + /* Build a linear or raid0 arrays without superblocks + * We cannot really do any checks, we just do it. + * For md_version < 0.90.0, we call REGISTER_DEV + * with the device numbers, and then + * START_MD giving the "geometry" + * geometry is 0xpp00cc + * where pp is personality: 1==linear, 2=raid0 + * cc = chunk size factor: 0==4k, 1==8k etc. + * + * For md_version >= 0.90.0 we call + * SET_ARRAY_INFO, ADD_NEW_DISK, RUN_ARRAY + * + */ + int i; + int vers; + struct stat stb; + if (raiddisks != subdevs) { + fprintf(stderr, Name ": requested %d devices in array but listed %d\n", + raiddisks, subdevs); + return 1; + } + + /* scan all devices, make sure they really are block devices */ + for (i=0; i<subdevs; i++) { + if (stat(subdev[i], &stb)) { + fprintf(stderr, Name ": Cannot find %s: %s\n", + subdev[i], strerror(errno)); + return 1; + } + if ((stb.st_mode & S_IFMT) != S_IFBLK) { + fprintf(stderr, Name ": %s is not a block device.\n", + subdev[i]); + return 1; + } + } + + vers = md_get_version(mdfd); + + /* looks Ok, go for it */ + if (vers >= 90000) { + mdu_array_info_t array; + array.level = level; + array.size = 0; + array.nr_disks = raiddisks; + array.raid_disks = raiddisks; + array.md_minor = 0; + if (fstat(mdfd, &stb)==0) + array.md_minor = MINOR(stb.st_rdev); + array.not_persistent = 0; + array.state = 0; /* not clean, but no errors */ + array.active_disks = raiddisks; + array.working_disks = raiddisks; + array.spare_disks = 0; + array.failed_disks = 0; + array.chunk_size = chunk*1024; + if (ioctl(mdfd, SET_ARRAY_INFO, &array)) { + fprintf(stderr, Name ": SET_ARRAY_INFO failed for %s: %s\n", + mddev, strerror(errno)); + return 1; + } + } + /* now add the devices */ + for (i=0; i<subdevs; i++) { + if (stat(subdev[i], &stb)) { + fprintf(stderr, Name ": Wierd: %s has disappeared.\n", + subdev[i]); + goto abort; + } + if ((stb.st_rdev & S_IFMT)!= S_IFBLK) { + fprintf(stderr, Name ": Wierd: %s is no longer a block device.\n", + subdev[i]); + goto abort; + } + if (vers> 90000) { + mdu_disk_info_t disk; + disk.number = i; + disk.raid_disk = i; + disk.state = 6; + disk.major = MAJOR(stb.st_rdev); + disk.minor = MINOR(stb.st_rdev); + if (ioctl(mdfd, ADD_NEW_DISK, &disk)) { + fprintf(stderr, Name ": ADD_NEW_DISK failed for %s: %s\n", + subdev[i], strerror(errno)); + goto abort; + } + } else { + if (ioctl(mdfd, REGISTER_DEV, &stb.st_rdev)) { + fprintf(stderr, Name ": REGISTER_DEV failed for %s.\n", + subdev[i], strerror(errno)); + goto abort; + } + } + } + /* now to start it */ + if (vers > 90000) { + mdu_param_t param; /* not used by syscall */ + if (ioctl(mdfd, RUN_ARRAY, param)) { + fprintf(stderr, Name ": RUN_ARRAY failed: %s\n", + strerror(errno)); + goto abort; + } + } else { + int arg; + arg=0; + while (chunk > 4096) { + arg++; + chunk >>= 1; + } + if (level == 0) + chunk |= 0x20000; + else chunk |= 0x10000; + if (ioctl(mdfd, START_MD, arg)) { + fprintf(stderr, Name ": START_MD failed: %s\n", + strerror(errno)); + goto abort; + } + } + fprintf(stderr, Name ": array %s built and started.\n", + mddev); + return 0; + + abort: + if (vers > 900000) + ioctl(mdfd, STOP_ARRAY, 0); + else + ioctl(mdfd, STOP_MD, 0); + return 1; + } + @@ -56,9 +56,9 @@ int Create(char *mddev, int mdfd, int maxdisc= -1, mindisc = -1; int i; int fail=0, warn=0; + struct stat stb; mdu_array_info_t array; - mdu_param_t param; if (md_get_version(mdfd) < 9000) { @@ -188,14 +188,42 @@ int Create(char *mddev, int mdfd, array.level = level; array.size = size; - array.nr_disks = raiddisks+sparedisks; + array.nr_disks = raiddisks+sparedisks+(level==4||level==5); array.raid_disks = raiddisks; + /* The kernel should *know* what md_minor we are dealing + * with, but it chooses to trust me instead. Sigh + */ array.md_minor = 0; + if (fstat(mdfd, &stb)==0) + array.md_minor = MINOR(stb.st_rdev); array.not_persistent = 0; - array.state = 0; /* not clean, but no errors */ - array.active_disks=0; - array.working_disks=0; - array.spare_disks=0; + if (level == 4 || level == 5) + array.state = 1; /* clean, but one drive will be missing */ + else + array.state = 0; /* not clean, but no errors */ + + /* There is lots of redundancy in these disk counts, + * raid_disks is the most meaningful value + * it describes the geometry of the array + * it is constant + * nr_disks is total number of used slots. + * it should be raid_disks+spare_disks + * spare_disks is the number of extra disks present + * see above + * active_disks is the number of working disks in + * active slots. (With raid_disks) + * working_disks is the total number of working disks, + * including spares + * failed_disks is the number of disks marked failed + * + * Ideally, the kernel would keep these (except raid_disks) + * up-to-date as we ADD_NEW_DISK, but it doesn't (yet). + * So for now, we assume that all raid and spare + * devices will be given. + */ + array.active_disks=raiddisks-(level==4||level==5); + array.working_disks=raiddisks+sparedisks; + array.spare_disks=sparedisks + (level==4||level==5); array.failed_disks=0; array.layout = layout; array.chunk_size = chunk*1024; @@ -217,13 +245,19 @@ int Create(char *mddev, int mdfd, } fstat(fd, &stb); disk.number = i; - disk.raid_disk = i; - disk.state = 6; /* active and in sync */ + if ((level==4 || level==5) && + disk.number >= raiddisks-1) + disk.number++; + disk.raid_disk = disk.number; + if (disk.raid_disk < raiddisks) + disk.state = 6; /* active and in sync */ + else + disk.state = 0; disk.major = MAJOR(stb.st_rdev); disk.minor = MINOR(stb.st_rdev); close(fd); if (ioctl(mdfd, ADD_NEW_DISK, &disk)) { - fprintf(stderr, Name ": ADD_NEW_DISK for %s failed: %s\b", + fprintf(stderr, Name ": ADD_NEW_DISK for %s failed: %s\n", subdev[i], strerror(errno)); return 1; } @@ -231,6 +265,7 @@ int Create(char *mddev, int mdfd, /* param is not actually used */ if (runstop == 1 || subdevs >= raiddisks) { + mdu_param_t param; if (ioctl(mdfd, RUN_ARRAY, ¶m)) { fprintf(stderr, Name ": RUN_ARRAY failed: %s\n", strerror(errno)); @@ -45,6 +45,9 @@ int Detail(char *dev) time_t atime; char *c; + mdp_super_t super; + int have_super = 0; + if (fd < 0) { fprintf(stderr, Name ": cannot open %s: %s\n", dev, strerror(errno)); @@ -102,11 +105,23 @@ int Detail(char *dev) c = map_num(r5layout, array.layout); printf(" Layout : %s\n", c?c:"-unknown-"); } - printf(" Chunk Size : %dK\n", array.chunk_size/1024); + switch (array.level) { + case 0: + case 4: + case 5: + printf(" Chunk Size : %dK\n", array.chunk_size/1024); + break; + case -1: + printf(" Rounding : %dK\n", array.chunk_size/1024); + break; + default: break; + } + printf("\n"); printf(" Number Major Minor RaidDisk State\n"); for (d= 0; d<array.nr_disks; d++) { mdu_disk_info_t disk; + char *dv; disk.number = d; if (ioctl(fd, GET_DISK_INFO, &disk) < 0) { fprintf(stderr, Name ": cannot get disk detail for disk %d: %s\n", @@ -119,7 +134,28 @@ int Detail(char *dev) if (disk.state & (1<<MD_DISK_ACTIVE)) printf(" active"); if (disk.state & (1<<MD_DISK_SYNC)) printf(" sync"); if (disk.state & (1<<MD_DISK_REMOVED)) printf(" removed"); + if ((dv=map_dev(disk.major, disk.minor))) { + printf(" %s", dv); + if (!have_super) { + /* try to read the superblock from this device + * to get more info + */ + int fd = open(dv, O_RDONLY); + if (fd >=0 && + load_super(fd, &super) ==0 && + super.ctime == array.ctime && + super.level == array.level) + have_super = 1; + } + } printf("\n"); } + if (have_super) { + if (super.minor_version >= 90) + printf(" UUID : %08x:%08x:%08x:%08x\n", super.set_uuid0, super.set_uuid1, + super.set_uuid2, super.set_uuid3); + else + printf(" UUID : %08x\n", super.set_uuid0); + } return 0; } @@ -29,6 +29,9 @@ #include "mdctl.h" +#if ! defined(__BIG_ENDIAN) && ! defined(__LITTLE_ENDIAN) +#error no endian defined +#endif #include "md_u.h" #include "md_p.h" int Examine(char *dev) @@ -47,7 +50,7 @@ int Examine(char *dev) * utime, state etc * */ - int fd = open(dev, O_RDONLY, 0); + int fd = open(dev, O_RDONLY); time_t atime; mdp_super_t super; int d; @@ -121,18 +124,32 @@ int Examine(char *dev) printf(" Working Drives : %d\n", super.working_disks); printf(" Failed Drives : %d\n", super.failed_disks); printf(" Spare Drives : %d\n", super.spare_disks); - printf(" - checksum not checked yet - \n"); + if (calc_sb_csum(&super) == super.sb_csum) + printf(" Checksum : %x - correct\n", super.sb_csum); + else + printf(" Checksum : %x - expected %x\n", super.sb_csum, calc_sb_csum(&super)); printf(" Events : %d.%d\n", super.events_hi, super.events_lo); printf("\n"); if (super.level == 5) { c = map_num(r5layout, super.layout); printf(" Layout : %s\n", c?c:"-unknown-"); } - printf(" Chunk Size : %dK\n", super.chunk_size/1024); + switch(super.level) { + case 0: + case 4: + case 5: + printf(" Chunk Size : %dK\n", super.chunk_size/1024); + break; + case -1: + printf(" Rounding : %dK\n", super.chunk_size/1024); + break; + default: break; + } printf("\n"); printf(" Number Major Minor RaidDisk State\n"); for (d= -1; d<(signed int)super.nr_disks; d++) { mdp_disk_t *dp; + char *dv; char nb[5]; if (d>=0) dp = &super.disks[d]; else dp = &super.this_disk; @@ -143,6 +160,8 @@ int Examine(char *dev) if (dp->state & (1<<MD_DISK_ACTIVE)) printf(" active"); if (dp->state & (1<<MD_DISK_SYNC)) printf(" sync"); if (dp->state & (1<<MD_DISK_REMOVED)) printf(" removed"); + if ((dv=map_dev(dp->major, dp->minor))) + printf(" %s", dv); printf("\n"); } return 0; @@ -27,9 +27,9 @@ # Australia # -CFLAGS = -Wall,error +CFLAGS = -Wall,error,strict-prototypes -ggdb -OBJS = mdctl.o config.o ReadMe.o util.o Manage.o Assemble.o Build.o Create.o Detail.o Examine.o +OBJS = mdctl.o config.o ReadMe.o util.o Manage.o Assemble.o Build.o Create.o Detail.o Examine.o dlink.o all : mdctl mdctl : $(OBJS) @@ -31,6 +31,10 @@ #include "md_u.h" #include "md_p.h" +#define REGISTER_DEV _IO (MD_MAJOR, 1) +#define START_MD _IO (MD_MAJOR, 2) +#define STOP_MD _IO (MD_MAJOR, 3) + int Manage_ro(char *devname, int fd, int readonly) { /* switch to readonly or rw @@ -60,7 +64,7 @@ int Manage_ro(char *devname, int fd, int readonly) } } else if (readonly < 0) { if (ioctl(fd, RESTART_ARRAY_RW, NULL)) { - fprintf(stderr, Name ": fail to re writable for %s: %s\n", + fprintf(stderr, Name ": failed to set writable for %s: %s\n", devname, strerror(errno)); return 1; } @@ -75,17 +79,26 @@ int Manage_runstop(char *devname, int fd, int runstop) */ mdu_array_info_t array; mdu_param_t param; /* unused */ + + if (runstop == -1 && md_get_version(fd) < 9000) { + if (ioctl(fd, STOP_MD, 0)) { + fprintf(stderr, Name ": stopping device %s failed: %s\n", + devname, strerror(errno)); + return 1; + } + } if (md_get_version(fd) < 9000) { fprintf(stderr, Name ": need md driver version 0.90.0 or later\n"); return 1; } + /* if (ioctl(fd, GET_ARRAY_INFO, &array)) { fprintf(stderr, Name ": %s does not appear to be active.\n", devname); return 1; } - + */ if (runstop>0) { if (ioctl(fd, RUN_ARRAY, ¶m)) { fprintf(stderr, Name ": failed to run array %s: %s\n", @@ -175,7 +188,7 @@ int Manage_subdevs(char *devname, int fd, case 'r': /* hot remove */ - /* FIXME check that is is a current member */ + /* FIXME check that it is a current member */ if (ioctl(fd, HOT_REMOVE_DISK, stb.st_rdev)) { fprintf(stderr, Name ": hot remove failed for %s: %s\n", devnames[i], strerror(errno)); @@ -29,7 +29,7 @@ #include "mdctl.h" -char Version[] = Name " - v0.3 - 14 June 2001\n"; +char Version[] = Name " - v0.4 - 26 July 2001\n"; /* * File: ReadMe.c * @@ -1,12 +1,22 @@ -- check superblock checksum in examine -- report "chunk" or "rounding" depending on raid level +- check superblock checksum in examine DONE +- report "chunk" or "rounding" depending on raid level DONE - report "linear" instead of "-1" for raid level DONE - decode ayout depending on raid level DONE - get Assemble to upgrade devices if force flag. - --verbose and --force flags. -- set md_minor, *_disks for Create +- set md_minor, *_disks for Create - DONE - for create raid5, how to choose between all working, but not insync one missing, one spare, insync +- when RUN_ARRAY, make sure *_disks counts are right + +- get --detail to extract extra stuff from superblock, + like uuid DONE +- --detail --brief to give a config file line +- parse config file. DONE +- test... + +- when --assemble --scan, if an underlying device is an md device, + then try to assemble that device first. @@ -28,7 +28,8 @@ */ #include "mdctl.h" - +#include "dlink.h" +#include <glob.h> /* * Read the config file * @@ -38,17 +39,299 @@ * 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 + * */ char DefaultConfFile[] = "/etc/mdctl.conf"; +char *keywords[] = { "device", "array", 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; + + + +int devline(char *line) +{ + char *w; + struct conf_dev *cd; + + for (w=dl_next(line); w != line; w=dl_next(w)) { + if (w[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_uuid_t uuidlist = NULL; + +void arrayline(char *line) +{ + char *w; + char *dev = NULL; + __u32 uuid[4]; + int uidset=0; + mddev_uuid_t mu; + + for (w=dl_next(line); w!=line; w=dl_next(w)) { + if (w[0] == '/') { + if (dev) + fprintf(stderr, Name ": only give one device per ARRAY line: %s and %s\n", + dev, w); + else dev = w; + } else if (strncasecmp(w, "uuid=", 5)==0 ) { + if (uidset) + fprintf(stderr, Name ": only specify uuid once, %s ignored.\n", + w); + else { + if (parse_uuid(w+5, uuid)) + uidset = 1; + else + fprintf(stderr, Name ": bad uuid: %s\n", w); + } + } else { + fprintf(stderr, Name ": unrecognised word on ARRAY line: %s\n", + w); + } + } + if (dev == NULL) + fprintf(stderr, Name ": ARRAY line with a device\n"); + else if (uidset == 0) + fprintf(stderr, Name ": ARRAY line %s has no uuid\n", dev); + else { + mu = malloc(sizeof(*mu)); + mu->devname = strdup(dev); + memcpy(mu->uuid, uuid, sizeof(uuid)); + mu->next = uuidlist; + uuidlist = mu; + } +} + +int loaded = 0; + +void load_conffile(char *conffile) +{ + FILE *f; + char *line; + + if (loaded) return; + if (conffile == NULL) + conffile = DefaultConfFile; + + f = fopen(conffile, "r"); + if (f ==NULL) + return; + + loaded = 1; + while ((line=conf_line(f))) { + switch(match_keyword(line)) { + case 0: /* DEVICE */ + devline(line); + break; + case 1: + arrayline(line); + break; + default: + fprintf(stderr, Name ": Unknown keyword %s\n", line); + } + free_line(line); + } + + +/* printf("got file\n"); */ +} + + mddev_uuid_t conf_get_uuids(char *conffile) { - return NULL; + load_conffile(conffile); + return uuidlist; } mddev_dev_t conf_get_devs(char *conffile) { - return NULL; + glob_t globbuf; + struct conf_dev *cd; + int flags = 0; + static mddev_dev_t dlist = NULL; + int i; + + while (dlist) { + mddev_dev_t t = dlist; + dlist = dlist->next; + free(t->devname); + free(t); + } + + load_conffile(conffile); + + for (cd=cdevlist; cd; cd=cd->next) { + glob(cd->name, flags, NULL, &globbuf); + flags |= GLOB_APPEND; + } + + for (i=0; i<globbuf.gl_pathc; i++) { + mddev_dev_t t = malloc(sizeof(*t)); + t->devname = strdup(globbuf.gl_pathv[i]); + t->next = dlist; + dlist = t; +/* printf("one dev is %s\n", t->devname);*/ + } + globfree(&globbuf); + + + return dlist; } diff --git a/dlink.c b/dlink.c new file mode 100644 index 00000000..de42632c --- /dev/null +++ b/dlink.c @@ -0,0 +1,76 @@ + +/* doubly linked lists */ +/* This is free software. No strings attached. No copyright claimed */ + +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#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 --git a/dlink.h b/dlink.h new file mode 100644 index 00000000..aa178e6c --- /dev/null +++ b/dlink.h @@ -0,0 +1,25 @@ + +/* doubley linked lists */ +/* This is free software. No strings attached. No copyright claimed */ + +struct __dl_head +{ + struct __dl_head * dh_prev; + struct __dl_head * 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) *((void**)&(((struct __dl_head*)(p))[-1].dh_next)) +#define dl_prev(p) *((void**)&(((struct __dl_head*)(p))[-1].dh_prev)) + +void *dl_head(); +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*); @@ -347,6 +347,7 @@ int main(int argc, char *argv[]) * There must be an mddev unless D or E or (A and scan) * If there is one, we open it. */ + if (mode !='D' && mode !='E' && ! (mode =='A' && scan)) { if (!mddev) { fprintf(stderr, Name ": an md device must be given in this mode\n"); @@ -366,15 +367,16 @@ int main(int argc, char *argv[]) } } + rv =0; switch(mode) { case '@':/* Management */ /* readonly, add/remove, readwrite, runstop */ - if (readonly>1) + if (readonly>0) rv = Manage_ro(mddev, mdfd, readonly); if (!rv && subdevs) rv = Manage_subdevs(mddev, mdfd, subdevs, subdev, devmodes); - if (!rv && readonly < 1) + if (!rv && readonly < 0) rv = Manage_ro(mddev, mdfd, readonly); if (!rv && runstop) rv = Manage_runstop(mddev, mdfd, runstop); @@ -78,6 +78,7 @@ extern char *map_num(mapping_t *map, int num); extern int map_name(mapping_t *map, char *name); extern mapping_t r5layout[], pers[]; +extern char *map_dev(int major, int minor); extern int Manage_ro(char *devname, int fd, int readonly); diff --git a/testconfig b/testconfig new file mode 100644 index 00000000..0ed8b2c0 --- /dev/null +++ b/testconfig @@ -0,0 +1,12 @@ +Hello there, "this is a" conf file + which has several lines +# there are comments + # losts of comments + with comments # really truely +Dev lines are needed + + and might have + "blanks in them, + they really could +I think + that empty "" strings are confusing
\ No newline at end of file diff --git a/testconfig2 b/testconfig2 new file mode 100644 index 00000000..6cd7a78f --- /dev/null +++ b/testconfig2 @@ -0,0 +1,3 @@ + +DEV /dev/hda* /dev/sd? +ARRAY /dev/md0 uuid=1234.5678.abcd.ef09:1234.5678.abcd.ef90 @@ -56,8 +56,10 @@ int parse_uuid(char *str, int uuid[4]) continue; else return 0; - uuid[hit/4] <<= 4; - uuid[hit/4] += n; + if (hit<32) { + uuid[hit/8] <<= 4; + uuid[hit/8] += n; + } hit++; } if (hit == 32) @@ -222,6 +224,31 @@ int load_super(int fd, mdp_super_t *super) return 0; } +int store_super(int fd, mdp_super_t *super) +{ + long size; + long long offset; + + if (ioctl(fd, BLKGETSIZE, &size)) + return 1; + + if (size < MD_RESERVED_SECTORS*2) + return 2; + + offset = MD_NEW_SIZE_SECTORS(size); + + offset *= 512; + + if (lseek64(fd, offset, 0)< 0LL) + return 3; + + if (write(fd, super, sizeof(*super)) != sizeof(*super)) + return 4; + + return 0; +} + + int check_ext2(int fd, char *name) { @@ -333,3 +360,67 @@ int map_name(mapping_t *map, char *name) } return -10; } + +/* + * 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; + +#define __USE_XOPEN_EXTENDED +#include <ftw.h> + + +int add_dev(const char *name, const struct stat *stb, int flag, struct FTW *s) +{ + if ((stb->st_mode&S_IFMT)== S_IFBLK) { + char *n = strdup(name); + struct devmap *dm = malloc(sizeof(*dm)); + if (dm) { + dm->major = MAJOR(stb->st_rdev); + dm->minor = MINOR(stb->st_rdev); + dm->name = n; + dm->next = devlist; + devlist = dm; + } + } + return 0; +} + +char *map_dev(int major, int minor) +{ + struct devmap *p; + if (!devlist_ready) { + nftw("/dev", add_dev, 10, FTW_PHYS); + devlist_ready=1; + } + + for (p=devlist; p; p=p->next) + if (p->major == major && + p->minor == minor) + return p->name; + return NULL; +} + + +int calc_sb_csum(mdp_super_t *super) +{ + unsigned int oldcsum = super->sb_csum; + unsigned long long newcsum = 0; /* FIXME why does this make it work?? */ + unsigned long csum; + int i; + unsigned int *superc = (int*) super; + super->sb_csum = 0; + + for(i=0; i<MD_SB_BYTES/4; i++) + newcsum+= superc[i]; + csum = (newcsum& 0xffffffff) + (newcsum>>32); + super->sb_csum = oldcsum; + return csum; +} |