X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=util.c;h=2f4ad9638e71fd2c9ed757d0bd1cdc1d227ded81;hb=dd0781e50555c32ff2f808ec46f4b03a5693ea47;hp=56618b23a46a57e936a5ed31949d1c3d3b312c49;hpb=56eb10c0b6e8f21540af444c8a28aa9e8f138ce6;p=thirdparty%2Fmdadm.git diff --git a/util.c b/util.c index 56618b23..2f4ad963 100644 --- a/util.c +++ b/util.c @@ -30,6 +30,7 @@ #include "mdadm.h" #include "md_p.h" #include +#include /* * Parse a 128 bit uuid in 4 integers @@ -91,7 +92,8 @@ int md_get_version(int fd) 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; @@ -101,18 +103,26 @@ int md_get_version(int fd) int get_linux_version() { struct utsname name; + char *cp; int a,b,c; if (uname(&name) <0) return -1; - if (sscanf(name.release, "%d.%d.%d", &a,&b,&c)!= 3) - 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; } int enough(int level, int raid_disks, int avail_disks) { switch (level) { + case -4: + return avail_disks>= 1; case -1: case 0: return avail_disks == raid_disks; @@ -121,6 +131,8 @@ int enough(int level, int raid_disks, int avail_disks) case 4: case 5: return avail_disks >= raid_disks-1; + case 6: + return avail_disks >= raid_disks-2; default: return 0; } @@ -197,8 +209,8 @@ int load_super(int fd, mdp_super_t *super) * 5 - no magic * 6 - wrong major version */ - long size; - long long offset; + unsigned long size; + unsigned long long offset; if (ioctl(fd, BLKGETSIZE, &size)) return 1; @@ -210,6 +222,8 @@ int load_super(int fd, mdp_super_t *super) offset *= 512; + ioctl(fd, BLKFLSBUF, 0); /* make sure we read current data */ + if (lseek64(fd, offset, 0)< 0LL) return 3; @@ -312,10 +326,10 @@ int check_raid(int fd, char *name) if (load_super(fd, &super)) return 0; /* Looks like a raid array .. */ - fprintf(stderr, Name ": %s appear to be part of a raid array:\n", + fprintf(stderr, Name ": %s appears to be part of a raid array:\n", name); crtime = super.ctime; - fprintf(stderr, " level=%d disks=%d ctime=%s", + fprintf(stderr, " level=%d devices=%d ctime=%s", super.level, super.raid_disks, ctime(&crtime)); return 1; } @@ -358,7 +372,7 @@ int map_name(mapping_t *map, char *name) return map->num; map++; } - return -10; + return UnSet; } /* @@ -373,11 +387,25 @@ struct devmap { } *devlist = NULL; int devlist_ready = 0; +#ifdef UCLIBC +char *map_dev(int major, int minor) +{ +#if 0 + fprintf(stderr, "Warning - fail to map %d,%d to a device name\n", + major, minor); +#endif + return NULL; +} +#else #define __USE_XOPEN_EXTENDED #include +#ifndef __dietlibc__ int add_dev(const char *name, const struct stat *stb, int flag, struct FTW *s) +#else +int add_dev(const char *name, const struct stat *stb, int flag) +#endif { if ((stb->st_mode&S_IFMT)== S_IFBLK) { char *n = strdup(name); @@ -393,23 +421,62 @@ int add_dev(const char *name, const struct stat *stb, int flag, struct FTW *s) return 0; } +int is_standard(char *dev) +{ + /* 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 + */ + dev = strrchr(dev, '/'); + if (!dev) + return 0; + if (strncmp(dev, "/d",2)==0) + dev += 2; + else if (strncmp(dev, "/md", 3)==0) + dev += 3; + else + return 0; + if (!*dev) + return 0; + while (isdigit(*dev)) + dev++; + if (*dev) + return 0; + return 1; +} + + +/* + * Find a block device with the right major/minor number. + * Avoid /dev/mdNN and /dev/md/dNN is possible + */ char *map_dev(int major, int minor) { - struct devmap *p; - if (!devlist_ready) { - nftw("/dev", add_dev, 10, FTW_PHYS); - devlist_ready=1; - } + struct devmap *p; + char *std = NULL; + if (!devlist_ready) { +#ifndef __dietlibc__ + nftw("/dev", add_dev, 10, FTW_PHYS); +#else + ftw("/dev", add_dev, 10); +#endif + devlist_ready=1; + } - for (p=devlist; p; p=p->next) - if (p->major == major && - p->minor == minor) - return p->name; - return NULL; + for (p=devlist; p; p=p->next) + if (p->major == major && + p->minor == minor) { + if (is_standard(p->name)) + std = p->name; + else + return p->name; + } + return std; } +#endif -int calc_sb_csum(mdp_super_t *super) +unsigned long calc_sb_csum(mdp_super_t *super) { unsigned int oldcsum = super->sb_csum; unsigned long long newcsum = 0; @@ -433,18 +500,124 @@ char *human_size(long long bytes) if (bytes < 5000*1024) buf[0]=0; else if (bytes < 2*1024LL*1024LL*1024LL) - sprintf(buf, " (%d.%02d MiB %d.%02d MB)", + sprintf(buf, " (%ld.%02ld MiB %ld.%02ld MB)", (long)(bytes>>20), - (long)(bytes&0xfffff)/(0x100000/100), + (long)((bytes&0xfffff)+0x100000/200)/(0x100000/100), (long)(bytes/1000/1000), - (long)((bytes%1000000)/10000) + (long)(((bytes%1000000)+5000)/10000) ); else - sprintf(buf, " (%d.%02d GiB %d.%02d GB)", + sprintf(buf, " (%ld.%02ld GiB %ld.%02ld GB)", (long)(bytes>>30), - (long)((bytes>>10)&0xfffff)/(0x100000/100), + (long)(((bytes>>10)&0xfffff)+0x100000/200)/(0x100000/100), (long)(bytes/1000LL/1000LL/1000LL), - (long)(((bytes/1000)%1000000)/10000) + (long)((((bytes/1000)%1000000)+5000)/10000) ); return buf; } + +char *human_size_brief(long long bytes) +{ + static char buf[30]; + + + if (bytes < 5000*1024) + sprintf(buf, "%ld.%02ldKiB", + (long)(bytes>>10), (long)(((bytes&1023)*100+512)/1024) + ); + else if (bytes < 2*1024LL*1024LL*1024LL) + sprintf(buf, "%ld.%02ldMiB", + (long)(bytes>>20), + (long)((bytes&0xfffff)+0x100000/200)/(0x100000/100) + ); + else + sprintf(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; +} + + + +char *get_md_name(int dev) +{ + /* find /dev/md%d or /dev/md/%d or make a device /dev/.tmp.md%d */ + /* if dev < 0, want /dev/md/d%d or find mdp in /proc/devices ... */ + static char devname[50]; + struct stat stb; + dev_t rdev; + char *dn; + + if (dev < 0) { + int mdp = get_mdp_major(); + if (mdp < 0) return NULL; + rdev = MKDEV(mdp, (-1-dev)<<6); + sprintf(devname, "/dev/md/d%d", -1-dev); + if (stat(devname, &stb) == 0 + && (S_IFMT&stb.st_mode) == S_IFBLK + && (stb.st_rdev == rdev)) + return devname; + } else { + rdev = MKDEV(MD_MAJOR, dev); + sprintf(devname, "/dev/md%d", dev); + if (stat(devname, &stb) == 0 + && (S_IFMT&stb.st_mode) == S_IFBLK + && (stb.st_rdev == rdev)) + return devname; + + sprintf(devname, "/dev/md/%d", dev); + if (stat(devname, &stb) == 0 + && (S_IFMT&stb.st_mode) == S_IFBLK + && (stb.st_rdev == rdev)) + return devname; + } + dn = map_dev(MAJOR(rdev), MINOR(rdev)); + if (dn) + return dn; + sprintf(devname, "/dev/.tmp.md%d", dev); + if (mknod(devname, S_IFBLK | 0600, rdev) == -1) + if (errno != EEXIST) + return NULL; + + if (stat(devname, &stb) == 0 + && (S_IFMT&stb.st_mode) == S_IFBLK + && (stb.st_rdev == rdev)) + return devname; + unlink(devname); + return NULL; +} + +void put_md_name(char *name) +{ + if (strncmp(name, "/dev/.tmp.md", 12)==0) + unlink(name); +}