X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fmdadm.git;a=blobdiff_plain;f=util.c;h=121ddbb731a28db5a4d890beaab2bf4031a22d01;hp=bb370dd4d94e71f7c5a40b04952349dacc0f4148;hb=b5e64645037e99b5f05c9499b27b422ae60d23a9;hpb=682c705194a869b882cd710d5f996142912db390 diff --git a/util.c b/util.c index bb370dd4..121ddbb7 100644 --- a/util.c +++ b/util.c @@ -1,7 +1,7 @@ /* - * mdctl - manage Linux "md" devices aka RAID arrays. + * mdadm - manage Linux "md" devices aka RAID arrays. * - * Copyright (C) 2001 Neil Brown + * Copyright (C) 2001-2002 Neil Brown * * * This program is free software; you can redistribute it and/or modify @@ -27,9 +27,10 @@ * Australia */ -#include "mdctl.h" +#include "mdadm.h" #include "md_p.h" #include +#include /* * Parse a 128 bit uuid in 4 integers @@ -56,8 +57,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) @@ -89,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; @@ -99,18 +103,28 @@ 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 10: return 1; /* a lie, but it is hard to tell */ + + case -4: + return avail_disks>= 1; case -1: case 0: return avail_disks == raid_disks; @@ -119,6 +133,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; } @@ -195,19 +211,29 @@ 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 dsize; + unsigned long long offset; - if (ioctl(fd, BLKGETSIZE, &size)) - return 1; +#ifdef BLKGETSIZE64 + if (ioctl(fd, BLKGETSIZE64, &dsize) != 0) +#endif + { + if (ioctl(fd, BLKGETSIZE, &size)) + return 1; + else + dsize = size << 9; + } - if (size < MD_RESERVED_SECTORS*2) + if (dsize < MD_RESERVED_SECTORS*2) return 2; - offset = MD_NEW_SIZE_SECTORS(size); + 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) return 3; @@ -222,6 +248,40 @@ int load_super(int fd, mdp_super_t *super) return 0; } +int store_super(int fd, mdp_super_t *super) +{ + unsigned long size; + unsigned long long dsize; + + long long offset; + +#ifdef BLKGETSIZE64 + if (ioctl(fd, BLKGETSIZE64, &dsize) != 0) +#endif + { + if (ioctl(fd, BLKGETSIZE, &size)) + return 1; + else + dsize = ((unsigned long long)size) << 9; + } + + if (dsize < MD_RESERVED_SECTORS*2) + 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; + + return 0; +} + + int check_ext2(int fd, char *name) { @@ -285,10 +345,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; } @@ -331,5 +391,253 @@ int map_name(mapping_t *map, char *name) return map->num; map++; } - return -10; + return UnSet; +} + + +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; +} + + +/* + * 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; + +#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); + 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; +} + +/* + * 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; + 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) { + if (is_standard(p->name)) + std = p->name; + else + return p->name; + } + return std; +} + +#endif + +unsigned long calc_sb_csum(mdp_super_t *super) +{ + unsigned int oldcsum = super->sb_csum; + unsigned long long newcsum = 0; + unsigned long csum; + int i; + unsigned int *superc = (int*) super; + super->sb_csum = 0; + + for(i=0; i>32); + super->sb_csum = oldcsum; + return csum; +} + +char *human_size(long long bytes) +{ + static char buf[30]; + + + if (bytes < 5000*1024) + buf[0]=0; + else if (bytes < 2*1024LL*1024LL*1024LL) + sprintf(buf, " (%ld.%02ld MiB %ld.%02ld MB)", + (long)(bytes>>20), + (long)((bytes&0xfffff)+0x100000/200)/(0x100000/100), + (long)(bytes/1000/1000), + (long)(((bytes%1000000)+5000)/10000) + ); + else + sprintf(buf, " (%ld.%02ld GiB %ld.%02ld GB)", + (long)(bytes>>30), + (long)(((bytes>>10)&0xfffff)+0x100000/200)/(0x100000/100), + (long)(bytes/1000LL/1000LL/1000LL), + (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); }