Package: quik
Version: 2.1-4
Severity: normal
Tags: patch

quik does not support linux metadevices (/dev/md). This is filed as a
normal bug as quik does not recognize an md device, and incorrectly
tries to find partitions on it. 
The included patch fixes the problem by adding limited md support to
quik -- the included README.md lists the current limitations. It was
generated against the 2.1-4 version from sid.


diff -Naur quik.orig/include/linux/raid/md_u.h quik/include/linux/raid/md_u.h
--- quik.orig/include/linux/raid/md_u.h 1970-01-01 01:00:00.000000000 +0100
+++ quik/include/linux/raid/md_u.h      2005-02-28 20:21:13.000000000 +0100
@@ -0,0 +1,116 @@
+/*
+   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)
+
+/* 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)
+
+/* 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_param_s
+{
+       int                     personality;    /* 1,2,3,4 */
+       int                     chunk_size;     /* in bytes */
+       int                     max_fault;      /* unused for now */
+} mdu_param_t;
+
+#endif 
+
diff -Naur quik.orig/include/quik_md.h quik/include/quik_md.h
--- quik.orig/include/quik_md.h 1970-01-01 01:00:00.000000000 +0100
+++ quik/include/quik_md.h      2005-03-03 20:44:31.000000000 +0100
@@ -0,0 +1,101 @@
+/* 
+ * quik-md.h - definitions for md handling in quik
+ *
+ * Copyright (C) 2005 Simon Vallet <[EMAIL PROTECTED]>
+ *
+ * Information retrieval code for md devices is derived from 
+ * Detail.c in mdadm version 1.9.0, and therefore:
+ *
+ * Copyright (C) 2001-2002 Neil Brown <[EMAIL PROTECTED]>
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _QUIKMD_H
+#define _QUIKMD_H
+
+#define __u32 u_int32_t
+#define __u64 u_int64_t
+
+#define MD_MAJOR 9
+#define DEV_BUFSZ 1024
+
+#define u32   u_int32_t
+#define u8    u_int8_t
+
+#include <sys/ioctl.h>
+#include <asm/ioctl.h>
+
+/* From md_p.h */
+#define MD_SB_DISKS 27
+#include <linux/raid/md_u.h>
+
+struct devmap {
+    int major, minor;
+    char *name;
+    struct devmap *next;
+};
+
+typedef struct mapping {
+        char *name;
+        int num;
+} mapping_t;
+
+#define  __USE_XOPEN_EXTENDED
+#include <ftw.h>
+
+char *map_num(mapping_t *, int);
+char *map_dev(int, int);
+int is_standard(char *, int *);
+int add_dev(const char *, const struct stat *, int, struct FTW *);
+int digit_offset (const char *);
+
+//void fatal (const char *);
+
+typedef struct dev_info {
+  char * bootdev;    /* Physical device, e.g. /dev/hda */
+  char * spart;      /* Filesystem device for second.b, e.g. /dev/hda2 */
+  int cpart;         /* Conffile part. number */
+  int part_block;    /* Block # of partition map entry */
+  int secsize;       /* Disk sector size */
+  int first_bootable; /* Part. map entry # of 1st bootable part */
+  unsigned long doff; /* Start of part. containing second.b */
+  struct first_info finfo; /* Boot block structure */
+} dev_info_t;
+
+typedef struct mdev_info {
+  char * metadev;    /* Metadevice, e.g. /dev/md0, if necessary */
+  char * fs_dev;     /* Device containing the filesystem */
+  dev_info_t ** devs; 
+  unsigned int bs;
+  unsigned int nsect;
+  unsigned char ndevs;
+  int rlevel;
+} mdev_info_t;
+
+#define BOOTDEV(dev,i) ((dev)->devs[(i)]->bootdev)
+#define SPART(dev,i) ((dev)->devs[(i)]->spart)
+
+dev_info_t * new_dev_info (unsigned char);
+void free_dev_info (dev_info_t *);
+int md_get_version (int);
+mdev_info_t * md_get_info (const char *);
+
+dev_info_t * new_dev_info ();
+void free_dev_info (dev_info_t *);
+mdev_info_t * new_mdev_info (unsigned char);
+void free_mdev_info (mdev_info_t *);
+
+#endif
diff -Naur quik.orig/quik/Makefile quik/quik/Makefile
--- quik.orig/quik/Makefile     2005-03-08 20:24:47.700579456 +0100
+++ quik/quik/Makefile  2005-03-08 20:32:22.918375832 +0100
@@ -1,10 +1,12 @@
-all:   quik
+objects= quik_md.o quik.o
 
 COPTS = -O -Wall
 CFLAGS = -I../include $(COPTS)
 
-quik: quik.c
-       $(CC) $(CFLAGS) -o quik quik.c
+all: quik
+
+quik: $(objects)
+       $(CC) $(CFLAGS) -o quik $(objects)
 
 clean:
        rm -f *.o *~ quik
diff -Naur quik.orig/quik/quik.c quik/quik/quik.c
--- quik.orig/quik/quik.c       2005-03-08 20:24:47.704578848 +0100
+++ quik/quik/quik.c    2005-03-08 20:44:29.577906000 +0100
@@ -2,6 +2,8 @@
 
    Copyright (C) 1996 Paul Mackerras.
 
+   Copyright (C) 2005 Simon Vallet for the MD handling code
+
    Derived from silo.c in the silo-0.6.4 distribution, therefore:
    
    Copyright (C) 1996 Maurizio Plaza
@@ -33,12 +35,14 @@
 #include <endian.h>
 #include <fcntl.h>
 #include <dirent.h>
-#include <layout.h>
 #include <sys/ioctl.h>
-
 #include <linux/fs.h>
 #include <ext2fs/ext2_fs.h>
+
+#include <layout.h>
 #include <asm/mac-part.h>
+#include <quik_md.h>
+
 
 #define DFL_CONFIG     "/etc/quik.conf"
 #define ALT_CONFIG     "/etc/milo.conf"
@@ -70,14 +74,7 @@
                         + (((x) & 0xff00) << 8) + (((x) & 0xff) << 24))
 #define swab_16(x)     ((((x) >> 8) & 0xff) + (((x) & 0xff) << 8))
 
-unsigned nsect;                        /* # (512-byte) sectors per f.s. block 
*/
-unsigned bs;                   /* f.s. block size */
-int part_block;                        /* block # of partition map entry */
-int secsize;                   /* disk sector size */
-int first_bootable;            /* part map entry # of 1st bootable part */
-unsigned long doff;            /* start of partition containing 2nd boot */
 char *first, *second, *old;    /* File names */
-struct first_info finfo;
 int verbose;
 
 void fatal(char *fmt,...)  __attribute__ ((noreturn));
@@ -107,83 +104,106 @@
     return -1;
 }
 
-void read_sb(char *device, char *bootdev)
+int part_from_dev (char * spart)
 {
-    int fd, partno, part;
+  char * p = spart + strlen(spart);
+  while (p > spart && isdigit(p[-1]))
+    --p;
+  return atoi(p);
+}
+
+
+void read_sb (mdev_info_t * devs)
+{
+    int fd, partno, part, i;
     int upart, maxpart;
     struct mac_partition *mp;
     struct mac_driver_desc *md;
-    char *p;
     char buff[512];
 
-    if ((fd = open(device, O_RDONLY)) == -1)
-       fatal("Cannot open %s", device);
-    bs = check_fs(fd);
-    if (bs == -1)
+    if ((fd = open(devs->fs_dev, O_RDONLY)) == -1)
+       fatal("Cannot open %s", devs->fs_dev);
+    devs->bs = check_fs(fd);
+    if (devs->bs == -1)
        fatal("Filesystems other than ext2 are not supported");
     close(fd);
 
-    p = device + strlen(device);
-    while (p > device && isdigit(p[-1]))
-       --p;
-    partno = atoi(p);
-    if (partno == 0)
-       fatal("Can't determine partition number for %s", device);
-    upart = 0;
-    mp = (struct mac_partition *) buff;
-    md = (struct mac_driver_desc *) buff;
-    if ((fd = open(bootdev, O_RDONLY)) == -1)
-       fatal("Can't open %s", bootdev);
-    if (read(fd, buff, sizeof (buff)) != sizeof (buff))
-       fatal("Error reading %s (block 0)", bootdev);
-    if (md->signature != MAC_DRIVER_MAGIC)
-       fatal("%s is not a mac-formatted disk", bootdev);
-    secsize = md->block_size;
-    maxpart = 1;
-    doff = 0;
-    for (part = 1; part <= maxpart; ++part) {
-       lseek(fd, part * secsize, 0);
+    for (i=0; i<devs->ndevs; i++) {
+      if (devs->devs[i]->bootdev) { /* Handle "missing" raid devices */
+       partno = part_from_dev(SPART(devs,i));
+       if (partno == 0)
+         fatal("Can't determine partition number for %s", SPART(devs,i));
+       upart = 0;
+       mp = (struct mac_partition *) buff;
+       md = (struct mac_driver_desc *) buff;
+       if ((fd = open(devs->devs[i]->bootdev, O_RDONLY)) == -1)
+         fatal("Can't open %s", BOOTDEV(devs, i));
        if (read(fd, buff, sizeof (buff)) != sizeof (buff))
-           fatal("Error reading partition map from %s", bootdev);
-       if (mp->signature != MAC_PARTITION_MAGIC)
+         fatal("Error reading %s (block 0)", BOOTDEV(devs, i));
+       if (md->signature != MAC_DRIVER_MAGIC)
+         fatal("%s is not a mac-formatted disk", BOOTDEV(devs, i));
+
+       devs->devs[i]->secsize = md->block_size;
+       devs->devs[i]->doff = 0;
+       maxpart = 1;
+       for (part = 1; part <= maxpart; ++part) {
+         lseek(fd, part * devs->devs[i]->secsize, 0);
+
+         if (read(fd, buff, sizeof (buff)) != sizeof (buff))
+           fatal("Error reading partition map from %s", BOOTDEV(devs, i));
+         if (mp->signature != MAC_PARTITION_MAGIC)
            break;
-       if (part == 1)
+         if (part == 1)
            maxpart = mp->map_count;
-       else if (maxpart != mp->map_count)
+         else if (maxpart != mp->map_count)
            break;
-       if (first_bootable == 0 && (mp->status & STATUS_BOOTABLE) != 0
-           && strcasecmp(mp->processor, "PowerPC") == 0)
-           first_bootable = part;
-       if (++upart == partno) {
+
+         if (devs->devs[i]->first_bootable == 0 
+             && (mp->status & STATUS_BOOTABLE) != 0
+             && strcasecmp(mp->processor, "PowerPC") == 0)
+           devs->devs[i]->first_bootable = part;
+
+         if (++upart == partno) {
            /* This is the one we want */
-           part_block = part;
-           doff = mp->start_block * (secsize >> 9);
+           devs->devs[i]->part_block = part;
+           devs->devs[i]->doff = mp->start_block * (devs->devs[i]->secsize >> 
9);
            break;
+         }
        }
+       if (upart < partno)
+         fatal("Couldn't locate partition %d on %s", partno, BOOTDEV(devs, i));
+      }
     }
-    if (upart < partno)
-       fatal("Couldn't locate partition %d on %s", partno, bootdev);
 }
 
-void make_bootable(char *device, char *spart)
+void make_bootable (mdev_info_t * devs)
 {
-    int fd;
-    struct mac_partition *mp;
-    char buff[512];
+  int fd; int i;
+  struct mac_partition *mp;
+  char buff[512];
+  off_t seek_offset;
 
-    if (part_block == 0)
-       return;
+  for (i=0; i<devs->ndevs; i++) {
+    if (devs->devs[i]->part_block == 0)
+      return;
     if (verbose)
-       printf("Making %s bootable (map entry %d)\n", spart, part_block);
-    if (first_bootable > 0 && first_bootable < part_block)
-       fprintf(stderr, "Warning: prior partition (entry %d) is bootable\n",
-               first_bootable);
-    if ((fd = open(device, O_RDWR)) < 0)
-       fatal("Cannot open %s for writing\n", device);
-    lseek(fd, part_block * secsize, 0);
-    if (read(fd, buff, sizeof(buff)) != sizeof(buff))
-       fatal("Error reading partition map entry %d from %s\n", part_block,
-             device);
+       printf("Making %s bootable (map entry %d)\n", 
+              SPART(devs, i), 
+              devs->devs[i]->part_block);
+    if (devs->devs[i]->first_bootable > 0 
+       && devs->devs[i]->first_bootable < devs->devs[i]->part_block)
+      fprintf(stderr, "Warning: prior partition (entry %d) is bootable\n",
+             devs->devs[i]->first_bootable);
+    if ((fd = open(BOOTDEV(devs,i), O_RDWR)) < 0)
+       fatal("Cannot open %s for writing\n", BOOTDEV(devs,i));
+    seek_offset = (off_t)devs->devs[i]->part_block * devs->devs[i]->secsize;
+    lseek(fd, seek_offset, 0);
+    if (read(fd, buff, sizeof(buff)) != sizeof(buff)) {
+      close(fd);
+      fatal("Error reading partition map entry %d from %s\n", 
+           devs->devs[i]->part_block,
+           BOOTDEV(devs,i));
+    }
     mp = (struct mac_partition *) buff;
     mp->status |= STATUS_BOOTABLE;
     mp->boot_start = 0;
@@ -193,31 +213,41 @@
     mp->boot_entry = FIRST_BASE;
     mp->boot_entry2 = 0;
     strncpy(mp->processor, "PowerPC", sizeof(mp->processor));
-    if (lseek(fd, part_block * secsize, 0) < 0
-       || write(fd, buff, sizeof(buff)) != sizeof(buff))
-       fatal("Couldn't make %s%d bootable: write error\n", device,
-             part_block);
+    if (lseek(fd, seek_offset, 0) < 0
+       || write(fd, buff, sizeof(buff)) != sizeof(buff)) {
+      close(fd);
+      fatal("Couldn't make %s%d bootable: write error\n", 
+           BOOTDEV(devs,i),
+           devs->devs[i]->part_block);
+    }
+    close(fd);
+  }
 }
 
-int get_partition_blocks(char *filename)
+int get_partition_blocks(char *filename, mdev_info_t * devs)
 {
     int fd;
-    int block, i;
+    int block, i, j;
     struct stat st;
 
     if ((fd = open(filename, O_RDONLY)) == -1)
        fatal("Cannot find %s", filename);
     if (fstat(fd, &st) < 0)
         fatal("Couldn't stat %s", filename);
-    finfo.blocksize = bs;
-    nsect = bs >> 9;
-    for (i = 0;; i++) {
-       block = i;
-       if (i * bs >= st.st_size || ioctl(fd, FIBMAP, &block) < 0 || !block)
+    devs->nsect = devs->bs >> 9;
+    for (j=0; j<devs->ndevs; j++) {
+      if (SPART(devs,j)) {
+       devs->devs[j]->finfo.blocksize = devs->bs;
+       
+       for (i = 0;; i++) {
+         block = i;
+         if (i * devs->bs >= st.st_size || ioctl(fd, FIBMAP, &block) < 0 || 
!block)
            break;
-       finfo.blknos[i] = block * nsect + doff;
+         devs->devs[j]->finfo.blknos[i] = block * devs->nsect + 
devs->devs[j]->doff;
+       }
+       devs->devs[j]->finfo.nblocks = i;
+      }
     }
-    finfo.nblocks = i;
     close(fd);
     return 0;
 }
@@ -238,22 +268,36 @@
         return strdup(path);
 }
 
-void write_block_table(char *device, char *config_file, int partno)
+void write_block_table(mdev_info_t *devs, char *config_file)
 {
-    int fd;
+    int fd, i;
+    struct first_info * finfo_p = NULL; 
 
-    if (verbose)
-       printf("Writing block table to boot block on %s\n", device);
-    strncpy(finfo.quik_vers, "QUIK" VERSION, sizeof(finfo.quik_vers));
-    finfo.second_base = SECOND_BASE;
-    finfo.conf_part = partno;
-    strncpy(finfo.conf_file, config_file, sizeof(finfo.conf_file));
-    if ((fd = open(device, O_RDWR)) == -1)
-       fatal("Cannot open %s", device);
+    for (i=0; i<devs->ndevs; i++) {
+      if (SPART(devs,i)) {
+       if (verbose)
+         printf("Writing block table to boot block on %s\n", SPART(devs,i));
+       strncpy(devs->devs[i]->finfo.quik_vers, 
+               "QUIK" VERSION, 
+               sizeof(devs->devs[i]->finfo.quik_vers));
+       devs->devs[i]->finfo.second_base = SECOND_BASE;
+       devs->devs[i]->finfo.conf_part = devs->devs[i]->cpart;
+       strncpy(devs->devs[i]->finfo.conf_file, 
+               config_file, 
+               sizeof(devs->devs[i]->finfo.conf_file));
+       finfo_p = &(devs->devs[i]->finfo); /* All should be equal */
+      }
+    }
+    /* Seems we have to have all our bootable md devices on
+     * the SAME partitions , e.g. /dev/hda2 & /dev/hdc2.
+     * seems difficult to circumvent as we write the block table to /dev/md?
+     */
+    if ((fd = open(devs->fs_dev, O_RDWR)) == -1)
+      fatal("Cannot open %s", devs->fs_dev);
     if (lseek(fd, FIRST_INFO_OFF, SEEK_SET) != FIRST_INFO_OFF)
-       fatal("Seek error on %s", device);
-    if (write(fd, &finfo, sizeof(finfo)) != sizeof(finfo))
-       fatal("Couldn't update boot block on %s", device);
+      fatal("Seek error on %s", devs->fs_dev);
+    if (write(fd, finfo_p, sizeof(struct first_info)) != sizeof(struct 
first_info))
+       fatal("Couldn't update boot block on %s", devs->fs_dev);
     close(fd);
 }
 
@@ -337,8 +381,8 @@
         fatal("Couldn't seek on %s", device);
     if (write(fd, buff, rc) != rc)
         fatal("Couldn't write quik bootblock to %s", device);
-    close(fd);
     fclose(fp);
+    close(fd);
 }
 
 char *find_dev(int number)
@@ -421,23 +465,58 @@
     }
 }
 
+mdev_info_t * get_dev_info (const char * basedev, int is_md, int is_raid, int 
inc_name, const struct stat st)
+{
+  mdev_info_t * out;
+  char buffer[DEV_BUFSZ];
+  /* No partitions on md devices,
+     but this macro gets the correct md minor */
+  int part = PART(st.st_dev);
+
+  if (is_md) {
+    /* We need to have the device before we can get any info */
+    strcpy(buffer, basedev);
+    if (part >= 0) { sprintf(buffer+strlen(buffer), "%d", part); }
+    
+    out = md_get_info(buffer);
+    out->fs_dev = out->metadev;
+  } else {
+    out = new_mdev_info(1);
+
+    strncpy(buffer, basedev, DEV_BUFSZ);
+    if (inc_name) { buffer[7] += UNIT(st.st_dev); }
+    out->devs[0]->bootdev = (char *)malloc(strlen(buffer)+1);
+    strcpy(out->devs[0]->bootdev, buffer);
+
+    if (is_raid) { strcat(buffer, "p"); }
+    if (part != 0) { 
+      sprintf(buffer+strlen(buffer), "%d", (is_raid) ? part & 7 : part);
+    }
+    out->devs[0]->spart = (char *)malloc(strlen(buffer)+1);
+    strcpy(out->devs[0]->spart, buffer);
+    out->fs_dev = out->devs[0]->spart;
+  }
+
+  return out;
+}
+
 int main(int argc,char **argv)
 {
     char *name = NULL, *config_file, *install = NULL, *secondary, *backup;
-    int c;
+    int c; int i;
     int version = 0;
     struct stat st1, st2;
     int force_backup = 0;
     int config_file_partno = 1;
     char *p, *basedev=NULL;
-    char bootdev[1024];
-    char spart[1024];
     char buffer[1024];
     int force = 0;
-    int inc_name, raid_dev;
+    int inc_name, raid_dev, md_dev;
     extern int optind;
     extern char *optarg;
 
+    /* md */
+    mdev_info_t * devs = NULL;
 
     /*
      * Test if we're being run on a chrp machine.  We don't
@@ -524,7 +603,8 @@
     unit_shift = 6;
     part_mask = 0x3f;
     inc_name = 1;
-       raid_dev = 0;
+    raid_dev = 0;
+    md_dev = 0;
     switch (MAJOR(st1.st_dev)) {
     case SD_MAJOR:
        unit_shift = 4;
@@ -557,6 +637,11 @@
                                fatal("We only support the 2 first system 
drives for now");
        }
        break;
+    case MD_MAJOR:
+      basedev = "/dev/md";
+      inc_name = 0;
+      md_dev = 1;
+      break;
     default:
        p = find_dev(st1.st_dev);
        if (p == NULL)
@@ -566,24 +651,15 @@
        part_mask = 0;
        inc_name = 0;
     }
-    strcpy(bootdev, basedev);
-    if (inc_name)
-       bootdev[7] += UNIT(st1.st_dev);
-    strcpy(spart, bootdev);
-    if (raid_dev)
-       strcat(spart,"p");
-    if (PART(st1.st_dev) != 0) {
-       if (raid_dev)
-               sprintf(spart+strlen(spart), "%d", PART(st1.st_dev) & 7);
-       else
-               sprintf(spart+strlen(spart), "%d", PART(st1.st_dev));
-    }
 
-    if (verbose)
-       printf("Second-stage loader is on %s\n", spart);
+    devs = get_dev_info(basedev, md_dev, raid_dev, inc_name, st1);
 
-    backup = chrootcpy (backup);
+    if (devs->metadev && devs->rlevel != 1)
+      fatal("RAID level other than 1 (mirror) are not supported");
 
+    if (verbose)
+       printf("Second-stage loader is on %s\n", devs->fs_dev);
+   
     if (config_file == NULL) {
        config_file = chrootcpy(DFL_CONFIG);
        if (stat(config_file, &st2) < 0) {
@@ -594,44 +670,74 @@
                config_file = p;
            }
        }
-    } else
+    } else {
        config_file = chrootcpy (config_file);
+    }
+
+    if (verbose)
+      printf("Conffile is %s\n", config_file);
 
     if (stat(config_file, &st2) >= 0) {
-       if (MAJOR(st2.st_dev) != MAJOR(st1.st_dev)
-           || UNIT(st2.st_dev) != UNIT(st1.st_dev)
-           || PART(st2.st_dev) != PART(st1.st_dev))
-            fatal("Config file %s has to be on the %s device (any partition)",
-                 config_file, bootdev);
-       strcpy(buffer, config_file);
-       config_file = resolve_to_dev(buffer, st2.st_dev);
+      /* If we have a metadevice, the following test 
+       * prevents having a separate /boot device, which should be
+       * possible in theory. But checking for PART() seems to make this
+       * impossible even for non-md devices -- OK for now.
+       */
+      if (MAJOR(st2.st_dev) != MAJOR(st1.st_dev)
+         || UNIT(st2.st_dev) != UNIT(st1.st_dev)
+         || PART(st2.st_dev) != PART(st1.st_dev))
+       fatal("Config file %s has to be on the %s device (any partition)",
+             config_file, BOOTDEV(devs, 0));
+      strcpy(buffer, config_file);
+      buffer[strlen(config_file)] = 0x00;
+      
+      config_file = resolve_to_dev(buffer, st2.st_dev);
+      if (devs->metadev) {
+       /* We are positive that conffile and second.b are 
+        *  on the same md device. Just get the part # from spart
+        */
+       for (i=0; i<devs->ndevs; i++) {
+         if (SPART(devs,i)) {      
+           devs->devs[i]->cpart = part_from_dev(SPART(devs,i));
+           if (devs->devs[i]->cpart == 0)
+             fatal("Can't determine partition number for %s\n", SPART(devs,i));
+         }
+       }
+      } else {
        if (inc_name)
-           if(raid_dev)
-               config_file_partno = PART(st2.st_dev) & 7;
-           else
-            config_file_partno = PART(st2.st_dev);
+         if(raid_dev)
+           config_file_partno = PART(st2.st_dev) & 7;
+         else
+           config_file_partno = PART(st2.st_dev);
        else
-           config_file_partno = 1;
+         config_file_partno = 1;
        if (verbose)
-           printf("Config file is on partition %d\n", config_file_partno);
+         printf("Config file is on partition %d\n", config_file_partno);       
+      }
     }
+    
+    backup = chrootcpy (backup);
+
     if (backup && !force_backup) {
         if (stat(backup, &st2) < 0)
             force_backup = 1;
     }
-    read_sb(spart, bootdev);
 
-    if (!examine_bootblock(spart, backup, force_backup)
+    read_sb(devs);
+
+    if (!examine_bootblock(devs->fs_dev, backup, force_backup)
        || install || force) {
-        if (!install)
-            install = chrootcpy(DFL_PRIMARY);
-        else if (*install == '/')
-            install = chrootcpy(install);
-       install_first_stage(spart, install);
-       make_bootable(bootdev, spart);
+      if (!install)
+       install = chrootcpy(DFL_PRIMARY);
+      else if (*install == '/')
+       install = chrootcpy(install);
+      install_first_stage(devs->fs_dev, install);
+      make_bootable(devs);
     }
-    get_partition_blocks(secondary);
-    write_block_table(spart, config_file, config_file_partno);
+    get_partition_blocks(secondary, devs);
+    write_block_table(devs, config_file);
+    
+    free_mdev_info(devs);
     sync();
     exit(0);
 }
diff -Naur quik.orig/quik/quik_md.c quik/quik/quik_md.c
--- quik.orig/quik/quik_md.c    1970-01-01 01:00:00.000000000 +0100
+++ quik/quik/quik_md.c 2005-03-08 20:23:03.994345000 +0100
@@ -0,0 +1,313 @@
+/*
+ * quik_md.c -- This file implements /dev/md device handling for quik.
+ *
+ * Copyright (C) 2005 Simon Vallet <[EMAIL PROTECTED]>
+ *
+ * Information retrieval code for md devices is derived from 
+ * Detail.c in mdadm version 1.9.0, and therefore:
+ *
+ * Copyright (C) 2001-2002 Neil Brown <[EMAIL PROTECTED]>
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <limits.h>
+#include <errno.h>
+
+#include <layout.h>
+#include <quik_md.h>
+
+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},
+        { NULL, 0}
+};
+
+struct devmap * devlist = NULL;
+int devlist_ready = 0;
+
+/* From quik.c */
+void fatal(char *fmt,...)  __attribute__ ((noreturn));
+
+mdev_info_t * md_get_info (const char * device)
+{
+
+  int d; int i=0; char * c;
+  int vers; int mdev_fd;
+  mdu_array_info_t array;
+  mdev_info_t * out = NULL;
+
+  if ((mdev_fd = open(device, O_RDONLY)) > 0) {
+    vers = md_get_version(mdev_fd);
+    if (vers > 0) {
+      if (ioctl(mdev_fd, GET_ARRAY_INFO, &array) < 0) {
+       close(mdev_fd);
+       fatal("Couldn't get array info for device %s\n", device);
+      }
+  
+      out = new_mdev_info(array.raid_disks);
+      out->rlevel = array.level;
+
+      /* Not needed for the moment */
+      c = map_num(pers, array.level);
+
+      /* fprintf(stderr, "ARRAY %s level=%s num-devices=%d\n",
+        md_dev, c?c:"unknown", array.raid_disks); */
+  
+      /* Get devices */
+      for (d=0; d < MD_SB_DISKS; d++) {
+       mdu_disk_info_t disk;
+       char *dv;
+       int o;
+       disk.number = d;
+       if (ioctl(mdev_fd, GET_DISK_INFO, &disk) < 0) { continue; }
+       if (d > array.raid_disks &&
+           disk.major == 0 &&
+           disk.minor == 0) { continue; }
+    
+       if ((dv=map_dev(disk.major, disk.minor))) {
+         out->devs[i]->spart = (char *) malloc(strlen(dv)+1);
+         strcpy(out->devs[i]->spart, dv);
+         o = digit_offset(out->devs[i]->spart);
+         out->devs[i]->bootdev = (char *) malloc(o+1);
+         strncpy(out->devs[i]->bootdev, out->devs[i]->spart, o);
+         out->devs[i]->bootdev[o+1] = 0x00;
+         i++;
+       }
+      }
+      
+      out->metadev = (char *)malloc(strlen(device)+1);
+      strcpy(out->metadev, device);
+      out->metadev[strlen(device)] = 0x00;
+    } else {
+      close(mdev_fd);
+      fatal("%s does not seem to be an md device. Exiting.", device);
+    }
+    close(mdev_fd);
+  } else {
+    fatal("Could not open device %s.\n", device);
+  }
+
+  return out;
+}
+
+int md_get_version (int fd)
+{
+    mdu_version_t vers;
+    struct stat stb;
+
+    if (fstat(fd, &stb)<0) {
+      return -1;
+    }
+    if ((S_IFMT&stb.st_mode) != S_IFBLK) {
+      fprintf(stderr, "This is not a block device.\n");
+      return -1;
+    }
+
+    if (ioctl(fd, RAID_VERSION, &vers) == 0) {
+        return  (vers.major*10000) + (vers.minor*100) + vers.patchlevel;
+    }
+    
+    if (errno == EACCES) {
+      perror("Could not access the given device");
+      return -1;
+    } else {
+      perror("get_version");
+    }
+ 
+    if (major(stb.st_rdev) == MD_MAJOR)
+      return (3600);
+   
+    return -1;
+}
+
+/*
+ * Returns the offset of the first digit
+ */
+int digit_offset (const char * str)
+{
+  int l; int o = -1;
+  
+  if (str) {
+    l = strlen(str);
+    while (++o<l && !isdigit(str[o]));
+  }
+  return o;
+}
+
+
+char * map_num(mapping_t *map, int num)
+{
+  while (map->name) {
+    if (map->num == num)
+      return map->name;
+    map++;
+  }
+  return NULL;
+}
+
+/*
+ * Find a block device with the right major/minor number.
+ * Avoid /dev/mdNN and /dev/md/dNN if possible
+ */
+char * map_dev(int major, int minor)
+{
+        struct devmap *p;
+        char *std = NULL;
+        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) {
+                        if (is_standard(p->name, NULL))
+                                std = p->name;
+                        else
+                                return p->name;
+                }
+        return std;
+}
+
+
+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)
+                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;
+}
+
+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;
+}
+
+/* Does NOT allocate space for individual strings, 
+ * i.e. bootdevs[i] or metadev 
+ */
+mdev_info_t * new_mdev_info (unsigned char ndevs)
+{
+  int i;
+  mdev_info_t * out = (mdev_info_t *)malloc(sizeof(mdev_info_t));
+  
+  out->ndevs = ndevs;
+  out->bs = out->nsect = 0;
+  out->devs = (dev_info_t **)malloc(ndevs*sizeof(dev_info_t *));
+  for (i=0; i<ndevs; i++) {
+    out->devs[i] = new_dev_info();
+  }
+  out->metadev = out->fs_dev = NULL;
+  out->rlevel = INT_MAX;
+
+  return out;
+}
+
+dev_info_t * new_dev_info ()
+{
+  dev_info_t * out = (dev_info_t *)malloc(sizeof(dev_info_t));
+
+  out->spart = out->bootdev = NULL;
+  out->part_block = out->secsize = 0;
+  out->first_bootable = 0;
+  out->doff = 0;
+  out->cpart = 0;
+
+  return out;
+}
+
+void free_mdev_info(mdev_info_t * obs)
+{
+  int i;
+
+  if (obs) {
+    /* fs_dev is a convenience pointer, not free()ed */
+    if (obs->metadev) free(obs->metadev);
+    if (obs->devs) {
+      for (i=0; i<obs->ndevs; i++) {
+       free_dev_info(obs->devs[i]);
+      }
+      free(obs->devs);
+    }
+    free(obs);
+  }
+}
+
+void free_dev_info (dev_info_t * obs)
+{
+  if (obs) {
+    if (obs->bootdev) free(obs->bootdev);
+    if (obs->spart) free(obs->spart);
+    free(obs);  
+  }
+}
diff -Naur quik.orig/README.md quik/README.md
--- quik.orig/README.md 1970-01-01 01:00:00.000000000 +0100
+++ quik/README.md      2005-03-08 20:29:49.317726680 +0100
@@ -0,0 +1,33 @@
+
+-----------------------------
+README -- MD support for quik
+-----------------------------
+
+This version of quik includes linux-style /dev/md support, with the
+following limitations :
+
+* It supports n-way mirrors (RAID1 arrays) only, and it is unlikely
+that support for other RAID levels will be added, unless we can 
+find a reliable way to get the conffile partition number on 
+a striped filesystem.
+
+* Further, the bootable metadevice (typically /) *must* be assembled
+from partitions having the same partition number (e.g. /dev/hda2 and 
+/dev/hdc2, *not* /dev/hda2 and /dev/hdc3). This is necessary because
+we write the bootblock to the metadevice, not the underlying 
+partitions. Again, it is unlikely that this will change.
+
+* The conffile *must* reside on the bootable partition/metadevice.
+This means that a separate /boot partition will *not* work, unless
+the configuration file is in /boot.
+
+* This version does not recognize spare devices, and will try
+to write a boot block on them -- if you have any spare drives in 
+your array, remove them before running quik. You can always re-add
+them later
+This will be fixed in a future version.
+
+* LVM volumes are not supported, but will be if at all possible.
+
+
+Simon Vallet -- 2005/03





-- 
To UNSUBSCRIBE, email to [EMAIL PROTECTED]
with a subject of "unsubscribe". Trouble? Contact [EMAIL PROTECTED]

Reply via email to