]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - util.c
Add mbr pseudo metadata handler.
[thirdparty/mdadm.git] / util.c
diff --git a/util.c b/util.c
index 25f1e56ae01d05277765ef6c4779ac08d6a11f75..c93b0a7ab81b632fa743e66e54e7edd6ad2bcdbe 100644 (file)
--- a/util.c
+++ b/util.c
@@ -65,55 +65,7 @@ struct blkpg_partition {
        char volname[BLKPG_VOLNAMELTH]; /* volume label */
 };
 
-/* partition table structures so we can check metadata position
- * against the end of the last partition.
- * Only handle MBR ant GPT partition tables.
- */
-struct MBR_part_record {
-  __u8 bootable;
-  __u8 first_head;
-  __u8 first_sector;
-  __u8 first_cyl;
-  __u8 part_type;
-  __u8 last_head;
-  __u8 last_sector;
-  __u8 last_cyl;
-  __u32 first_sect_lba;
-  __u32 blocks_num;
-};
-
-struct MBR {
-       __u8 pad[446];
-       struct MBR_part_record parts[4];
-       __u16 magic;
-} __attribute__((packed));
-
-struct GPT_part_entry {
-  unsigned char type_guid[16];
-  unsigned char partition_guid[16];
-  __u64 starting_lba;
-  __u64 ending_lba;
-  unsigned char attr_bits[8];
-  unsigned char name[72];
-} __attribute__((packed));
-
-struct GPT {
-       __u64 magic;
-       __u32 revision;
-       __u32 header_size;
-       __u32 crc;
-       __u32 pad1;
-       __u64 current_lba;
-       __u64 backup_lba;
-       __u64 first_lba;
-       __u64 last_lba;
-       __u8 guid[16];
-       __u64 part_start;
-       __u32 part_cnt;
-       __u32 part_size;
-       __u32 part_crc;
-       __u8 pad2[420];
-} __attribute__((packed));
+#include "part.h"
 
 /* Force a compilation error if condition is true */
 #define BUILD_BUG_ON(condition) ((void)BUILD_BUG_ON_ZERO(condition))
@@ -124,14 +76,6 @@ struct GPT {
    aren't permitted). */
 #define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
 
-
-/* MBR/GPT magic numbers */
-#define        MBR_SIGNATURE_MAGIC     __cpu_to_le16(0xAA55)
-#define        GPT_SIGNATURE_MAGIC     __cpu_to_le64(0x5452415020494645ULL)
-
-#define MBR_PARTITIONS               4
-#define MBR_GPT_PARTITION_TYPE       0xEE
-
 /*
  * Parse a 128 bit uuid in 4 integers
  * format is 32 hexx nibbles with options :.<space> separator
@@ -959,19 +903,33 @@ int dev_open(char *dev, int flags)
        int minor;
 
        if (!dev) return -1;
+       flags |= O_DIRECT;
 
        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:%d",
-                        (int)getpid(), major, minor);
-               if (mknod(devname, S_IFBLK|0600, makedev(major, minor))==0) {
-                       fd = open(devname, flags|O_DIRECT);
-                       unlink(devname);
+               char *path = map_dev(major, minor, 0);
+               if (path)
+                       fd = open(path, flags);
+               if (fd < 0) {
+                       snprintf(devname, sizeof(devname), "/dev/.tmp.md.%d:%d:%d",
+                                (int)getpid(), major, minor);
+                       if (mknod(devname, S_IFBLK|0600, makedev(major, minor))==0) {
+                               fd = open(devname, flags);
+                               unlink(devname);
+                       }
+               }
+               if (fd < 0) {
+                       snprintf(devname, sizeof(devname), "/tmp/.tmp.md.%d:%d:%d",
+                                (int)getpid(), major, minor);
+                       if (mknod(devname, S_IFBLK|0600, makedev(major, minor))==0) {
+                               fd = open(devname, flags);
+                               unlink(devname);
+                       }
                }
        } else
-               fd = open(dev, flags|O_DIRECT);
+               fd = open(dev, flags);
        return fd;
 }
 
@@ -1035,7 +993,12 @@ void wait_for(char *dev, int fd)
                dprintf("%s: timeout waiting for %s\n", __func__, dev);
 }
 
-struct superswitch *superlist[] = { &super0, &super1, &super_ddf, &super_imsm, NULL };
+struct superswitch *superlist[] =
+{
+       &super0, &super1,
+       &super_ddf, &super_imsm,
+       &mbr,
+       NULL };
 
 #if !defined(MDASSEMBLE) || defined(MDASSEMBLE) && defined(MDASSEMBLE_AUTO)
 
@@ -1131,7 +1094,7 @@ struct supertype *guess_super(int fd)
         */
        struct superswitch  *ss;
        struct supertype *st;
-       unsigned long besttime = 0;
+       time_t besttime = 0;
        int bestsuper = -1;
        int i;
 
@@ -1207,7 +1170,7 @@ static int get_gpt_last_partition_end(int fd, unsigned long long *endofpart)
        struct GPT_part_entry *part;
        unsigned long long curr_part_end;
        unsigned all_partitions, entry_size;
-       int part_nr;
+       unsigned part_nr;
 
        *endofpart = 0;
 
@@ -1266,7 +1229,7 @@ static int get_last_partition_end(int fd, unsigned long long *endofpart)
        struct MBR boot_sect;
        struct MBR_part_record *part;
        unsigned long long curr_part_end;
-       int part_nr;
+       unsigned part_nr;
        int retval = 0;
 
        *endofpart = 0;
@@ -1376,7 +1339,7 @@ int open_container(int fd)
                        continue;
                n = read(dfd, buf, sizeof(buf));
                close(dfd);
-               if (n <= 0 || n >= sizeof(buf))
+               if (n <= 0 || (unsigned)n >= sizeof(buf))
                        continue;
                buf[n] = 0;
                if (sscanf(buf, "%d:%d", &major, &minor) != 2)
@@ -1392,6 +1355,148 @@ int open_container(int fd)
        return -1;
 }
 
+struct superswitch *version_to_superswitch(char *vers)
+{
+       int i;
+
+       for (i = 0; superlist[i]; i++) {
+               struct superswitch *ss = superlist[i];
+
+               if (strcmp(vers, ss->name) == 0)
+                       return ss;
+       }
+
+       return NULL;
+}
+
+int is_container_member(struct mdstat_ent *mdstat, char *container)
+{
+       if (mdstat->metadata_version == NULL ||
+           strncmp(mdstat->metadata_version, "external:", 9) != 0 ||
+           !is_subarray(mdstat->metadata_version+9) ||
+           strncmp(mdstat->metadata_version+10, container, strlen(container)) != 0 ||
+           mdstat->metadata_version[10+strlen(container)] != '/')
+               return 0;
+
+       return 1;
+}
+
+int is_subarray_active(char *subarray, char *container)
+{
+       struct mdstat_ent *mdstat = mdstat_read(0, 0);
+       struct mdstat_ent *ent;
+
+       for (ent = mdstat; ent; ent = ent->next) {
+               if (is_container_member(ent, container)) {
+                       char *inst = &ent->metadata_version[10+strlen(container)+1];
+
+                       if (!subarray || strcmp(inst, subarray) == 0)
+                               break;
+               }
+       }
+
+       free_mdstat(mdstat);
+
+       return ent != NULL;
+}
+
+int is_container_active(char *container)
+{
+       return is_subarray_active(NULL, container);
+}
+
+/* open_subarray - opens a subarray in a container
+ * @dev: container device name
+ * @st: supertype with only ->subarray set
+ * @quiet: block reporting errors flag
+ *
+ * On success returns an fd to a container and fills in *st
+ */
+int open_subarray(char *dev, struct supertype *st, int quiet)
+{
+       struct mdinfo *mdi;
+       int fd, err = 1;
+
+       fd = open(dev, O_RDWR|O_EXCL);
+       if (fd < 0) {
+               if (!quiet)
+                       fprintf(stderr, Name ": Couldn't open %s, aborting\n",
+                               dev);
+               return 2;
+       }
+
+       st->devnum = fd2devnum(fd);
+       if (st->devnum == NoMdDev) {
+               if (!quiet)
+                       fprintf(stderr,
+                               Name ": Failed to determine device number for %s\n",
+                               dev);
+               goto close_fd;
+       }
+
+       mdi = sysfs_read(fd, st->devnum, GET_VERSION|GET_LEVEL);
+       if (!mdi) {
+               if (!quiet)
+                       fprintf(stderr, Name ": Failed to read sysfs for %s\n",
+                               dev);
+               goto close_fd;
+       }
+
+       if (mdi->array.level != UnSet) {
+               if (!quiet)
+                       fprintf(stderr, Name ": %s is not a container\n", dev);
+               goto free_sysfs;
+       }
+
+       st->ss = version_to_superswitch(mdi->text_version);
+       if (!st->ss) {
+               if (!quiet)
+                       fprintf(stderr,
+                               Name ": Operation not supported for %s metadata\n",
+                               mdi->text_version);
+               goto free_sysfs;
+       }
+
+       st->devname = devnum2devname(st->devnum);
+       if (!st->devname) {
+               if (!quiet)
+                       fprintf(stderr, Name ": Failed to allocate device name\n");
+               goto free_sysfs;
+       }
+
+       if (st->ss->load_super(st, fd, NULL)) {
+               if (!quiet)
+                       fprintf(stderr, Name ": Failed to find subarray-%s in %s\n",
+                               st->subarray, dev);
+               goto free_name;
+       }
+
+       if (!st->loaded_container) {
+               if (!quiet)
+                       fprintf(stderr, Name ": %s is not a container\n", dev);
+               goto free_super;
+       }
+
+       err = 0;
+
+ free_super:
+       if (err)
+               st->ss->free_super(st);
+ free_name:
+       if (err)
+               free(st->devname);
+ free_sysfs:
+       sysfs_free(mdi);
+ close_fd:
+       if (err)
+               close(fd);
+
+       if (err)
+               return -1;
+       else
+               return fd;
+}
+
 int add_disk(int mdfd, struct supertype *st,
             struct mdinfo *sra, struct mdinfo *info)
 {
@@ -1493,7 +1598,7 @@ int stat2devnum(struct stat *st)
        if ((S_IFMT & st->st_mode) == S_IFBLK) {
                if (major(st->st_rdev) == MD_MAJOR)
                        return minor(st->st_rdev);
-               else if (major(st->st_rdev) == get_mdp_major())
+               else if (major(st->st_rdev) == (unsigned)get_mdp_major())
                        return -1- (minor(st->st_rdev)>>MdpMinorShift);
 
                /* must be an extended-minor partition. Look at the
@@ -1524,15 +1629,17 @@ int fd2devnum(int fd)
        return NoMdDev;
 }
 
-char *pid_dir = VAR_RUN;
-
 int mdmon_pid(int devnum)
 {
        char path[100];
        char pid[10];
        int fd;
        int n;
-       sprintf(path, "%s/%s.pid", pid_dir, devnum2devname(devnum));
+       char *devname = devnum2devname(devnum);
+
+       sprintf(path, "%s/%s.pid", MDMON_DIR, devname);
+       free(devname);
+
        fd = open(path, O_RDONLY | O_NOATIME, 0);
 
        if (fd < 0)