int most_recent = 0;
if (!mddev && !scan) {
- fputs("mdctl: internal error - Assemble called with no devie or scan\n", stderr);
+ fputs(Name ": internal error - Assemble called with no devie or scan\n", stderr);
return 1;
}
if (!mddev) {
int found = 0;
device_list = conf_get_uuids(conffile);
if (!device_list) {
- fprintf(stderr, "mdctl: No devices found in config file\n");
+ fprintf(stderr, Name ": No devices found in config file\n");
return 1;
}
while (device_list) {
mdfd = open(device_list->devname, O_RDONLY, 0);
if (mdfd < 0) {
fprintf(stderr,
- "mdctl: error opening %s: %s\n",
+ Name ": error opening %s: %s\n",
device_list->devname,
strerror(errno));
continue;
}
if (found)
return 0;
- fprintf(stderr,"mdctl: Did not successful Assemble any devices\n");
+ fprintf(stderr,Name ": Did not successful Assemble any devices\n");
return 1;
}
*/
vers = md_get_version(mdfd);
if (vers <= 0) {
- fprintf(stderr, "mdctl: %s appears not to be an md device.\n");
+ fprintf(stderr, Name ": %s appears not to be an md device.\n");
return 1;
}
- if (vers < (90<<8)) {
- fprintf(stderr, "mdctl: Assemble requires driver version 0.90.0 or later.\n"
+ if (vers < 9000) {
+ fprintf(stderr, Name ": Assemble requires driver version 0.90.0 or later.\n"
" Upgrade your kernel or try --Build\n");
return 1;
}
- if (get_linux_version() < 0x020400)
+ if (get_linux_version() < 2004000)
old_linux = 1;
if (ioctl(mdfd, GET_ARRAY_INFO, &array)>=0) {
- fprintf(stderr, "mdctl: device %s already active - cannot assemble it\n",
+ fprintf(stderr, Name ": device %s already active - cannot assemble it\n",
mddev);
return 1;
}
device_list = device_list->next;
if (!device_list) {
- fprintf(stderr, "mdctl: --scan set and no uuid found for %s in config file.\n",
+ fprintf(stderr, Name ": --scan set and no uuid found for %s in config file.\n",
mddev);
return 1;
}
devlist = conf_get_devs(conffile);
if (subdevs == 0 && devlist == NULL) {
- fprintf(stderr, "mdctl: no devices given for %s\n", mddev);
+ fprintf(stderr, Name ": no devices given for %s\n", mddev);
return 1;
}
/* now for each device */
dfd = open(devname, O_RDONLY, 0);
if (dfd < 0) {
if (inargv || verbose)
- fprintf(stderr, "mdctl: cannot open device %s: %s\n",
+ fprintf(stderr, Name ": cannot open device %s: %s\n",
devname, strerror(errno));
continue;
}
if (fstat(dfd, &stb)< 0) {
/* Impossible! */
- fprintf(stderr, "mdctl: fstat failed for %s: %s\n",
+ fprintf(stderr, Name ": fstat failed for %s: %s\n",
devname, strerror(errno));
close(dfd);
continue;
}
if ((stb.st_mode & S_IFMT) != S_IFBLK) {
- fprintf(stderr, "mdctl: %d is not a block device.\n",
+ fprintf(stderr, Name ": %d is not a block device.\n",
devname);
close(dfd);
continue;
}
if (load_super(dfd, &super)) {
if (inargv || verbose)
- fprintf( stderr, "mdctl: no RAID superblock on %s\n",
+ fprintf( stderr, Name ": no RAID superblock on %s\n",
devname);
close(dfd);
continue;
close(dfd);
if (compare_super(&first_super, &super)) {
if (inargv || verbose)
- fprintf(stderr, "mdctl: superblock on %s doesn't match\n",
+ fprintf(stderr, Name ": superblock on %s doesn't match\n",
devname);
continue;
}
uuid_from_super(this_uuid, &first_super);
if (!same_uuid(this_uuid, uuid)) {
if (inargv || verbose)
- fprintf(stderr, "mdctl: %s has wrong uuid.\n",
+ fprintf(stderr, Name ": %s has wrong uuid.\n",
devname);
continue;
}
/* Ok, this one is at least worth considering */
if (devcnt >= MD_SB_DISKS) {
- fprintf(stderr, "mdctl: ouch - too many devices appear to be in this array. Ignoring %s\n",
+ fprintf(stderr, Name ": ouch - too many devices appear to be in this array. Ignoring %s\n",
devname);
continue;
}
}
if (devcnt == 0) {
- fprintf(stderr, "mdctl: no devices found for %s\n",
+ fprintf(stderr, Name ": no devices found for %s\n",
mddev);
return 1;
}
* not up-to-date, update the superblock
* and add it.
*/
- fprintf(stderr,"NoImplementedYet\n");
+ fprintf(stderr,"NotImplementedYet\n");
/* FIXME */
exit(2);
}
/* Almost ready to actually *do* something */
if (!old_linux) {
if (ioctl(mdfd, SET_ARRAY_INFO, NULL) != 0) {
- fprintf(stderr, "mdctl: SET_ARRAY_INFO failed for %s: %s\n",
+ fprintf(stderr, Name ": SET_ARRAY_INFO failed for %s: %s\n",
mddev, strerror(errno));
return 1;
}
disk.major = devices[j].major;
disk.minor = devices[j].minor;
if (ioctl(mdfd, ADD_NEW_DISK, &disk)!=0) {
- fprintf(stderr, "mdctl: failed to add %s to %s: %s\n",
+ fprintf(stderr, Name ": failed to add %s to %s: %s\n",
devices[j].devname,
mddev,
strerror(errno));
} else
okcnt--;
} else if (verbose)
- fprintf(stderr, "mdctl: no uptodate device for slot %d of %s\n",
+ fprintf(stderr, Name ": no uptodate device for slot %d of %s\n",
i, mddev);
}
if (runstop == 1 ||
enough(first_super.level, first_super.raid_disks, okcnt))) {
if (ioctl(mdfd, RUN_ARRAY, NULL)==0)
return 0;
- fprintf(stderr, "mdctl: failed to RUN_ARRAY %s: %s\n",
+ fprintf(stderr, Name ": failed to RUN_ARRAY %s: %s\n",
mddev, strerror(errno));
return 1;
}
*/
#include "mdctl.h"
+#include "md_u.h"
+#include "md_p.h"
int Create(char *mddev, int mdfd,
- int chunk, int level, int layout, int raiddisks, int sparedisks,
+ int chunk, int level, int layout, int size, int raiddisks, int sparedisks,
int subdevs, char *subdev[],
- int runstop)
+ int runstop, int verbose)
{
+ /*
+ * Create a new raid array.
+ *
+ * First check that necessary details are available
+ * (i.e. level, raid-disks)
+ *
+ * Then check each disk to see what might be on it
+ * and report anything interesting.
+ *
+ * If anything looks odd, and runstop not set,
+ * abort.
+ *
+ * SET_ARRAY_INFO and ADD_NEW_DISK, and
+ * if runstop==run, or raiddisks diskswere used,
+ * RUN_ARRAY
+ */
+ int minsize, maxsize;
+ int maxdisc= -1, mindisc = -1;
+ int i;
+ int fail=0, warn=0;
+
+ mdu_array_info_t array;
+ mdu_param_t param;
+
+
+ if (md_get_version(mdfd) < 9000) {
+ fprintf(stderr, Name ": Create requires md driver verison 0.90.0 or later\n");
+ return 1;
+ }
+ if (level == -10) {
+ fprintf(stderr,
+ Name ": a RAID level is needed to create an array.\n");
+ return 1;
+ }
+ if (raiddisks < 1) {
+ fprintf(stderr,
+ Name ": a number of --raid-disks must be given to create an array\n");
+ return 1;
+ }
+ if (raiddisks+sparedisks > MD_SB_DISKS) {
+ fprintf(stderr,
+ Name ": too many discs requested: %d+%d > %d\n",
+ raiddisks, sparedisks, MD_SB_DISKS);
+ return 1;
+ }
+ if (subdevs > raiddisks+sparedisks) {
+ fprintf(stderr, Name ": You have listed more disks (%d) than are in the array(%d)!\n", subdevs, raiddisks+sparedisks);
+ return 1;
+ }
+ /* now set some defaults */
+ if (layout == -1)
+ switch(level) {
+ default: /* no layout */
+ layout = 0;
+ break;
+ case 5:
+ layout = map_name(r5layout, "default");
+ if (verbose)
+ fprintf(stderr,
+ Name ": layout defaults to %s\n", map_num(r5layout, layout));
+ break;
+ }
+
+ if (chunk == 0) {
+ chunk = 64;
+ if (verbose)
+ fprintf(stderr, Name ": chunk size defaults to 64K\n");
+ }
+
+ /* now look at the subdevs */
+ for (i=0; i<subdevs; i++) {
+ char *dname = subdev[i];
+ int dsize, freesize;
+ int fd = open(dname, O_RDONLY, 0);
+ if (fd <0 ) {
+ fprintf(stderr, Name ": Cannot open %s: %s\n",
+ dname, strerror(errno));
+ fail=1;
+ continue;
+ }
+ if (ioctl(fd, BLKGETSIZE, &dsize)) {
+ fprintf(stderr, Name ": Cannot get size of %s: %s\n",
+ dname, strerror(errno));
+ fail = 1;
+ close(fd);
+ continue;
+ }
+ if (dsize < MD_RESERVED_SECTORS*2) {
+ fprintf(stderr, Name ": %s is too small: %dK\n",
+ dname, dsize/2);
+ fail = 1;
+ close(fd);
+ continue;
+ }
+ freesize = MD_NEW_SIZE_SECTORS(dsize);
+ freesize /= 2;
+
+ if (size && freesize < size) {
+ fprintf(stderr, Name ": %s is smaller that given size."
+ " %dK < %dK + superblock\n", dname, freesize, size);
+ fail = 1;
+ close(fd);
+ continue;
+ }
+ if (maxdisc< 0 || (maxdisc>=0 && freesize > maxsize)) {
+ maxdisc = i;
+ maxsize = freesize;
+ }
+ if (mindisc < 0 || (mindisc >=0 && freesize < minsize)) {
+ mindisc = i;
+ minsize = freesize;
+ }
+ warn |= check_ext2(fd, dname);
+ warn |= check_reiser(fd, dname);
+ warn |= check_raid(fd, dname);
+ close(fd);
+ }
+ if (fail) {
+ fprintf(stderr, Name ": create aborted\n");
+ return 1;
+ }
+ if (size == 0) {
+ if (mindisc == -1) {
+ fprintf(stderr, Name ": no size and no drives given - aborting create.\n");
+ return 1;
+ }
+ size = minsize;
+ if (verbose)
+ fprintf(stderr, Name ": size set to %dK\n", size);
+ }
+ if ((maxsize-size)*100 > maxsize) {
+ fprintf(stderr, Name ": largest drive (%s) exceed size (%dK) by more than 1%\n",
+ subdev[maxdisc], size);
+ warn = 1;
+ }
+
+ if (warn) {
+ if (runstop!= 1) {
+ if (!ask("Continue creating array? ")) {
+ fprintf(stderr, Name ": create aborted.\n");
+ return 1;
+ }
+ } else {
+ if (verbose)
+ fprintf(stderr, Name ": creation continuing despite oddities due to --run\n");
+ }
+ }
+
+ /* Ok, lets try some ioctls */
+
+ array.level = level;
+ array.size = size;
+ array.nr_disks = raiddisks+sparedisks;
+ array.raid_disks = raiddisks;
+ array.md_minor = 0;
+ array.not_persistent = 0;
+ array.state = 0; /* not clean, but no errors */
+ array.active_disks=0;
+ array.working_disks=0;
+ array.spare_disks=0;
+ array.failed_disks=0;
+ array.layout = layout;
+ 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;
+ }
+
+ for (i=0; i<subdevs; i++) {
+ int fd = open(subdev[i], O_RDONLY, 0);
+ struct stat stb;
+ mdu_disk_info_t disk;
+ if (fd < 0) {
+ fprintf(stderr, Name ": failed to open %s after earlier success - aborting\n",
+ subdev[i]);
+ return 1;
+ }
+ fstat(fd, &stb);
+ disk.number = i;
+ disk.raid_disk = i;
+ disk.state = 6; /* active and in sync */
+ 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",
+ subdev[i], strerror(errno));
+ return 1;
+ }
+ }
+
+ /* param is not actually used */
+ if (runstop == 1 || subdevs >= raiddisks) {
+ if (ioctl(mdfd, RUN_ARRAY, ¶m)) {
+ fprintf(stderr, Name ": RUN_ARRAY failed: %s\n",
+ strerror(errno));
+ return 1;
+ }
+ fprintf(stderr, Name ": array %s started.\n", mddev);
+ } else {
+ fprintf(stderr, Name ": not starting array - not enough discs.\n");
+ }
+ return 0;
}
mdu_array_info_t array;
int d;
time_t atime;
+ char *c;
if (fd < 0) {
- fprintf(stderr, "mdctl: cannot open %s: %s\n",
+ fprintf(stderr, Name ": cannot open %s: %s\n",
dev, strerror(errno));
return 1;
}
vers = md_get_version(fd);
if (vers < 0) {
- fprintf(stderr, "mdctl: %s does not appear to be an md device\n",
+ fprintf(stderr, Name ": %s does not appear to be an md device\n",
dev);
close(fd);
return 1;
}
- if (vers < (90<<8)) {
- fprintf(stderr, "mdctl: cannot get detail for md device %s: driver version too old.\n",
+ if (vers < 9000) {
+ fprintf(stderr, Name ": cannot get detail for md device %s: driver version too old.\n",
dev);
close(fd);
return 1;
}
if (ioctl(fd, GET_ARRAY_INFO, &array)<0) {
if (errno == ENODEV)
- fprintf(stderr, "mdctl: md device %s does not appear to be active.\n",
+ fprintf(stderr, Name ": md device %s does not appear to be active.\n",
dev);
else
- fprintf(stderr, "mdctl: cannot get array detail for %s: %s\n",
+ fprintf(stderr, Name ": cannot get array detail for %s: %s\n",
dev, strerror(errno));
close(fd);
return 1;
array.major_version, array.minor_version, array.patch_version);
atime = array.ctime;
printf(" Creation Time : %.24s\n", ctime(&atime));
- printf(" Raid Level : %d\n", array.level);
+ c = map_num(pers, array.level);
+ printf(" Raid Level : %s\n", c?c:"-unknown-");
printf(" Size : %d\n", array.size);
printf(" Raid Disks : %d\n", array.raid_disks);
printf(" Total Disks : %d\n", array.nr_disks);
printf(" Failed Drives : %d\n", array.failed_disks);
printf(" Spare Drives : %d\n", array.spare_disks);
printf("\n");
- printf(" Layout : %d\n", array.layout);
+ if (array.level == 5) {
+ c = map_num(r5layout, array.layout);
+ printf(" Layout : %s\n", c?c:"-unknown-");
+ }
printf(" Chunk Size : %dK\n", array.chunk_size/1024);
printf("\n");
printf(" Number Major Minor RaidDisk State\n");
mdu_disk_info_t disk;
disk.number = d;
if (ioctl(fd, GET_DISK_INFO, &disk) < 0) {
- fprintf(stderr, "mdctl: cannot get disk detail for disk %d: %s\n",
+ fprintf(stderr, Name ": cannot get disk detail for disk %d: %s\n",
d, strerror(errno));
continue;
}
time_t atime;
mdp_super_t super;
int d;
+ char *c;
int rv;
if (fd < 0) {
- fprintf(stderr,"mdctl: cannot open %s: %s\n",
+ fprintf(stderr,Name ": cannot open %s: %s\n",
dev, strerror(errno));
return 1;
}
close(fd);
switch(rv) {
case 1:
- fprintf(stderr, "mdctl: cannot find device size for %s: %s\n",
+ fprintf(stderr, Name ": cannot find device size for %s: %s\n",
dev, strerror(errno));
return 1;
case 2:
-/* fprintf(stderr, "mdctl: %s is too small for md: size is %ld sectors\n",
+/* fprintf(stderr, Name ": %s is too small for md: size is %ld sectors\n",
dev, size);
*/
- fprintf(stderr, "mdctl: %s is too small for md\n",
+ fprintf(stderr, Name ": %s is too small for md\n",
dev);
return 1;
case 3:
- fprintf(stderr, "mdctl: Cannot seek to superblock on %s: %s\n",
+ fprintf(stderr, Name ": Cannot seek to superblock on %s: %s\n",
dev, strerror(errno));
return 1;
case 4:
- fprintf(stderr, "mdctl: Cannot read superblock on %s\n",
+ fprintf(stderr, Name ": Cannot read superblock on %s\n",
dev);
return 1;
case 5:
- fprintf(stderr, "mdctl: No super block found on %s (Expected magic %08x, got %08x)\n",
+ fprintf(stderr, Name ": No super block found on %s (Expected magic %08x, got %08x)\n",
dev, MD_SB_MAGIC, super.md_magic);
return 1;
case 6:
- fprintf(stderr, "mdctl: Cannot interpret superblock on %s - version is %d\n",
+ fprintf(stderr, Name ": Cannot interpret superblock on %s - version is %d\n",
dev, super.major_version);
return 1;
}
atime = super.ctime;
printf(" Creation Time : %.24s\n", ctime(&atime));
- printf(" Raid Level : %d\n", super.level);
+ c=map_num(pers, super.level);
+ printf(" Raid Level : %s\n", c?c:"-unknown-");
printf(" Size : %d\n", super.size);
printf(" Raid Disks : %d\n", super.raid_disks);
printf(" Total Disks : %d\n", super.nr_disks);
printf(" - checksum not checked yet - \n");
printf(" Events : %d.%d\n", super.events_hi, super.events_lo);
printf("\n");
- printf(" Layout : %d\n", super.layout);
+ 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);
printf("\n");
printf(" Number Major Minor RaidDisk State\n");
dist : clean
./makedist
+
+TAGS :
+ etags *.h *.c
*/
#include "mdctl.h"
+#include "md_u.h"
+#include "md_p.h"
int Manage_ro(char *devname, int fd, int readonly)
{
+ /* switch to readonly or rw
+ *
+ * requires >= 0.90.0
+ * first check that array is runing
+ * use RESTART_ARRAY_RW or STOP_ARRAY_RO
+ *
+ */
+ mdu_array_info_t array;
+
+ 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 (readonly>0) {
+ if (ioctl(fd, STOP_ARRAY_RO, NULL)) {
+ fprintf(stderr, Name ": failed to set readonly for %s: %s\n",
+ devname, strerror(errno));
+ return 1;
+ }
+ } else if (readonly < 0) {
+ if (ioctl(fd, RESTART_ARRAY_RW, NULL)) {
+ fprintf(stderr, Name ": fail to re writable for %s: %s\n",
+ devname, strerror(errno));
+ return 1;
+ }
+ }
+ return 0;
}
int Manage_runstop(char *devname, int fd, int runstop)
{
+ /* Run or stop the array. array must already be configured
+ * required >= 0.90.0
+ */
+ mdu_array_info_t array;
+ mdu_param_t param; /* unused */
+
+ 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",
+ devname, strerror(errno));
+ return 1;
+ }
+ } else if (runstop < 0){
+ if (ioctl(fd, STOP_ARRAY, NULL)) {
+ fprintf(stderr, Name ": fail to re writable for %s: %s\n",
+ devname, strerror(errno));
+ return 1;
+ }
+ }
+ return 0;
}
int Manage_subdevs(char *devname, int fd,
int devcnt, char *devnames[], int devmodes[])
-{
+ {
+ /* do something to each dev.
+ * devmode can be
+ * 'a' - add the device
+ * try HOT_ADD_DISK
+ * If that fails EINVAL, try ADD_NEW_DISK
+ * 'r' - remove the device HOT_REMOVE_DISK
+ * 'f' - set the device faulty SET_DISK_FAULTY
+ */
+ mdu_array_info_t array;
+ mdu_disk_info_t disc;
+ struct stat stb;
+ int i,j;
+
+ if (ioctl(fd, GET_ARRAY_INFO, &array)) {
+ fprintf(stderr, Name ": cannot get array info for %s\n",
+ devname);
+ return 1;
+ }
+ for (i=0 ; i<devcnt; i++) {
+ if (stat(devnames[i], &stb)) {
+ fprintf(stderr, Name ": cannot find %s: %s\n",
+ devnames[i], strerror(errno));
+ return 1;
+ }
+ if ((stb.st_mode & S_IFMT) != S_IFBLK) {
+ fprintf(stderr, Name ": %s is not a block device.\n",
+ devnames[i]);
+ return 1;
+ }
+ switch(devmodes[i]){
+ default:
+ fprintf(stderr, Name ": internal error - devmode[%d]=%d\n",
+ i, devmodes[i]);
+ return 1;
+ case 'a':
+ /* add the device - hot or cold */
+ if (ioctl(fd, HOT_ADD_DISK, stb.st_rdev)==0) {
+ fprintf(stderr, Name ": hot added %s\n",
+ devnames[i]);
+ continue;
+ }
+ /* try ADD_NEW_DISK.
+ * we might be creating, we might be assembling,
+ * it is hard to tell.
+ * set up number/raid_disk/state just
+ * in case
+ */
+ for (j=0; j<array.nr_disks; j++) {
+ if (ioctl(fd, GET_DISK_INFO, &disc))
+ break;
+ if (disc.major==0 && disc.minor==0)
+ break;
+ if (disc.state & 8) /* removed */
+ break;
+ }
+ disc.number =j;
+ disc.raid_disk = j;
+ disc.state = 0;
+ disc.major = MAJOR(stb.st_rdev);
+ disc.minor = MINOR(stb.st_rdev);
+ if (ioctl(fd,ADD_NEW_DISK, &disc)) {
+ fprintf(stderr, Name ": add new disk failed for %s: %s\n",
+ devnames[i], strerror(errno));
+ return 1;
+ }
+ fprintf(stderr, Name ": added %s\n", devnames[i]);
+ break;
+
+ case 'r':
+ /* hot remove */
+ /* FIXME check that is 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));
+ return 1;
+ }
+ fprintf(stderr, Name ": hot removed %s\n", devnames[i]);
+ break;
+
+ case 'f': /* set faulty */
+ /* FIXME check current member */
+ if (ioctl(fd, SET_DISK_FAULTY, stb.st_rdev)) {
+ fprintf(stderr, Name ": set disk faulty failed for %s: %s\n",
+ devnames[i], strerror(errno));
+ return 1;
+ }
+ fprintf(stderr, Name ": set %s faulty in %s\n",
+ devnames[i], devname);
+ break;
+ }
+ }
+ return 0;
+
}
#include "mdctl.h"
-char Version[] = "mdctl - v0.2 - 06 June 2001\n";
+char Version[] = Name " - v0.3 - 14 June 2001\n";
/*
* File: ReadMe.c
*
* command, subsequent Manage commands can finish the job.
*/
-char short_options[]="-ABCDEhVvc:l:p:n:x:u:c:sarfRSow";
+char short_options[]="-ABCDEhVvc:l:p:n:x:u:c:z:sarfRSow";
struct option long_options[] = {
{"manage", 0, 0, '@'},
{"assemble", 0, 0, 'A'},
{"layout", 1, 0, 'p'},
{"raid-disks",1, 0, 'n'},
{"spare-disks",1,0, 'x'},
+ {"size" ,1, 0, 'z'},
/* For assemble */
{"uuid", 1, 0, 'u'},
" --layout= : same as --parity\n"
" --raid-disks= -n : number of active devices in array\n"
" --spare-disks= -x : number of spares (eXtras) to allow space for\n"
+" --size= -z : Size (in K) of each drive in RAID1/4/5 - optional\n"
"\n"
" For assemble:\n"
" --uuid= -u : uuid of array to assemble. Devices which don't\n"
" be run, though the presence of a '--run' can override this\n"
" caution.\n"
"\n"
+" If the --size option is given, it is not necessary to list any subdevices\n"
+" in this command. They can be added later, before a --run.\n"
+" If no --size is given, the apparent size of the smallest drive given\n"
+" is used.\n"
+"\n"
" The General management options that are valid with --create are:\n"
" --run : insist of running the array even if not all devices\n"
" are present or some look odd.\n"
" not yet documented\n"
"\n"
;
+
+
+/* name/number mappings */
+
+mapping_t r5layout[] = {
+ { "left_asymmetric", 0},
+ { "right_asymmetric", 1},
+ { "left_symmetric", 2},
+ { "right_symmetric", 3},
+
+ { "default", 2},
+ { "la", 0},
+ { "ra", 1},
+ { "ls", 2},
+ { "rs", 3},
+ { NULL, 0}
+};
+
+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},
+ { NULL, 0}
+};
--- /dev/null
+\f
+md_p.h,1316
+#define _MD_P_H\7f16,582
+#define MD_RESERVED_BYTES \7f44,1414
+#define MD_RESERVED_SECTORS \7f45,1453
+#define MD_RESERVED_BLOCKS \7f46,1508
+#define MD_NEW_SIZE_SECTORS(\7fMD_NEW_SIZE_SECTORS\ 148,1570
+#define MD_NEW_SIZE_BLOCKS(\7fMD_NEW_SIZE_BLOCKS\ 149,1659
+#define MD_SB_BYTES \7f51,1746
+#define MD_SB_WORDS \7f52,1773
+#define MD_SB_BLOCKS \7f53,1813
+#define MD_SB_SECTORS \7f54,1863
+#define MD_SB_GENERIC_OFFSET \7f59,1960
+#define MD_SB_PERSONALITY_OFFSET \7f60,1992
+#define MD_SB_DISKS_OFFSET \7f61,2028
+#define MD_SB_DESCRIPTOR_OFFSET \7f62,2060
+#define MD_SB_GENERIC_CONSTANT_WORDS \7f64,2098
+#define MD_SB_GENERIC_STATE_WORDS \7f65,2138
+#define MD_SB_GENERIC_WORDS \7f66,2175
+#define MD_SB_PERSONALITY_WORDS \7f67,2263
+#define MD_SB_DESCRIPTOR_WORDS \7f68,2299
+#define MD_SB_DISKS \7f69,2334
+#define MD_SB_DISKS_WORDS \7f70,2359
+#define MD_SB_RESERVED_WORDS \7f71,2423
+#define MD_SB_EQUAL_WORDS \7f72,2553
+#define MD_DISK_FAULTY \7f77,2691
+#define MD_DISK_ACTIVE \7f78,2752
+#define MD_DISK_SYNC \7f79,2814
+#define MD_DISK_REMOVED \7f80,2878
+typedef struct mdp_device_descriptor_s \7fmdp_device_descriptor_s\ 182,2946
+} mdp_disk_t;\7fmdp_disk_t\ 189,3310
+#define MD_SB_MAGIC \7f91,3325
+#define MD_SB_CLEAN \7f96,3390
+#define MD_SB_ERRORS \7f97,3413
+typedef struct mdp_superblock_s \7fmdp_superblock_s\ 199,3438
+} mdp_super_t;\7fmdp_super_t\ 1164,5820
+static inline __u64 md_event(\7f166,5836
+\f
+md_u.h,1118
+#define _MD_U_H\7f16,590
+#define RAID_VERSION \7f21,634
+#define GET_ARRAY_INFO \7f22,693
+#define GET_DISK_INFO \7f23,757
+#define PRINT_RAID_DEBUG \7f24,819
+#define RAID_AUTORUN \7f25,865
+#define CLEAR_ARRAY \7f28,929
+#define ADD_NEW_DISK \7f29,971
+#define HOT_REMOVE_DISK \7f30,1032
+#define SET_ARRAY_INFO \7f31,1078
+#define SET_DISK_INFO \7f32,1142
+#define WRITE_RAID_INFO \7f33,1186
+#define UNPROTECT_ARRAY \7f34,1232
+#define PROTECT_ARRAY \7f35,1278
+#define HOT_ADD_DISK \7f36,1322
+#define SET_DISK_FAULTY \7f37,1365
+#define RUN_ARRAY \7f40,1424
+#define START_ARRAY \7f41,1478
+#define STOP_ARRAY \7f42,1520
+#define STOP_ARRAY_RO \7f43,1561
+#define RESTART_ARRAY_RW \7f44,1605
+typedef struct mdu_version_s \7fmdu_version_s\ 146,1652
+} mdu_version_t;\7fmdu_version_t\ 150,1724
+typedef struct mdu_array_info_s \7fmdu_array_info_s\ 152,1742
+} mdu_array_info_t;\7fmdu_array_info_t\ 183,2516
+typedef struct mdu_disk_info_s \7fmdu_disk_info_s\ 185,2537
+} mdu_disk_info_t;\7fmdu_disk_info_t\ 195,2693
+typedef struct mdu_start_info_s \7fmdu_start_info_s\ 197,2713
+} mdu_start_info_t;\7fmdu_start_info_t\ 1106,2857
+typedef struct mdu_param_s\7fmdu_param_s\ 1108,2878
+} mdu_param_t;\7fmdu_param_t\ 1113,3014
+\f
+mdctl.h,823
+#define __USE_LARGEFILE64\7f30,1115
+#define MD_MAJOR \7f47,1491
+extern char short_options[\7f52,1531
+extern struct option long_options[\7f53,1560
+extern char Version[\7f54,1597
+extern char Version[], Usage[\7f54,1597
+extern char Version[], Usage[], Help[\7f54,1597
+extern char Version[], Usage[], Help[], Help_create[\7f54,1597
+extern char Version[], Usage[], Help[], Help_create[], Help_build[\7f54,1597
+extern char Version[], Usage[], Help[], Help_create[], Help_build[], Help_assemble[\7f54,1597
+typedef struct mddev_uuid_s \7fmddev_uuid_s\ 158,1762
+} *mddev_uuid_t;\7fmddev_uuid_t\ 162,1852
+typedef struct mddev_dev_s \7fmddev_dev_s\ 165,1918
+} *mddev_dev_t;\7fmddev_dev_t\ 168,1990
+#define ALGORITHM_LEFT_ASYMMETRIC \7f73,2044
+#define ALGORITHM_RIGHT_ASYMMETRIC \7f74,2080
+#define ALGORITHM_LEFT_SYMMETRIC \7f75,2117
+#define ALGORITHM_RIGHT_SYMMETRIC \7f76,2152
+\f
+Assemble.c,22
+int Assemble(\7f34,1171
+\f
+Build.c,19
+int Build(\7f32,1135
+\f
+Create.c,20
+int Create(\7f32,1135
+\f
+Detail.c,20
+int Detail(\7f34,1171
+\f
+Examine.c,21
+int Examine(\7f34,1171
+\f
+Manage.c,79
+int Manage_ro(\7f32,1135
+int Manage_runstop(\7f36,1191
+int Manage_subdevs(\7f40,1251
+\f
+ReadMe.c,231
+#define Name \7f32,1135
+char Version[\7f33,1156
+char short_options[\7f82,3241
+struct option long_options[\7f83,3297
+char Usage[\7f122,4441
+char Help[\7f127,4498
+char Help_create[\7f181,6989
+char Help_build[\7f203,7973
+char Help_assemble[\7f216,8513
+\f
+config.c,102
+char DefaultConfFile[\7f43,1371
+mddev_uuid_t conf_get_uuids(\7f45,1416
+mddev_dev_t conf_get_devs(\7f50,1482
+\f
+mdctl.c,40
+int main(\7f33,1153
+#define O(\7fO\ 1131,3313
+\f
+util.c,212
+int parse_uuid(\7f40,1354
+int md_get_version(\7f80,2091
+int get_linux_version(\7f99,2448
+int enough(\7f111,2639
+int same_uuid(\7f127,2889
+void uuid_from_super(\7f137,3018
+int compare_super(\7f151,3295
+int load_super(\7f185,4258
- check superblock checksum in examine
- report "chunk" or "rounding" depending on raid level
-- report "linear" instead of "-1" for raid level
-- decode ayout depending on raid level
+- 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.
\ No newline at end of file
+- --verbose and --force flags.
+
+- set md_minor, *_disks for Create
+- for create raid5, how to choose between
+ all working, but not insync
+ one missing, one spare, insync
exit 2
fi
set `grep '^char Version' ReadMe.c `
-echo version = $6
-base=mdctl-$6.tgz
+echo version = $7
+base=mdctl-$7.tgz
if [ -f $target/$base ]
then
echo $target/$base exists.
trap "rm $target/$base; exit" 1 2 3
( cd .. ; tar czvf - mdctl ) > $target/$base
chmod a+r $target/$base
-ls -l $target/$base
\ No newline at end of file
+ls -l $target/$base
int i;
int chunk = 0;
+ int size = 0;
int level = -10;
int layout = -1;
int raiddisks = 0;
case 'E':
/* setting mode - only once */
if (mode) {
- fprintf(stderr, "mdctl: --%s/-%c not allowed, mode already set to %s\n",
+ fprintf(stderr, Name ": --%s/-%c not allowed, mode already set to %s\n",
long_options[opt-'A'+1].name,
long_options[opt-'A'+1].val,
long_options[mode-'A'+1].name);
mddev = optarg;
else {
if (subdevs +1 >= MD_SB_DISKS) {
- fprintf(stderr, "mdctl: too many devices at %s - current limit -s %d\n",
+ fprintf(stderr, Name ": too many devices at %s - current limit -s %d\n",
optarg, MD_SB_DISKS);
exit(2);
}
case O('C','c'):
case O('B','c'): /* chunk or rounding */
if (chunk) {
- fprintf(stderr, "mdctl: chunk/rounding may only be specified once. "
+ fprintf(stderr, Name ": chunk/rounding may only be specified once. "
"Second value is %s.\n", optarg);
exit(2);
}
chunk = strtol(optarg, &c, 10);
- if (!optarg[0] || *c) {
- fprintf(stderr, "mdctl: invalid chunk/rounding value: %s\n",
+ if (!optarg[0] || *c || chunk<4 || ((chunk-1)&chunk)) {
+ fprintf(stderr, Name ": invalid chunk/rounding value: %s\n",
optarg);
exit(2);
}
continue;
+ case O('c','z'): /* size */
+ if (size) {
+ fprintf(stderr, Name ": size may only be specified once. "
+ "Second value is %s.\n", optarg);
+ exit(2);
+ }
+ size = strtol(optarg, &c, 10);
+ if (!optarg[0] || *c || size < 4) {
+ fprintf(stderr, Name ": invalid size: %s\n",
+ optarg);
+ exit(2);
+ }
+ continue;
+
case O('C','l'):
case O('B','l'): /* set raid level*/
if (level != -10) {
- fprintf(stderr, "mdctl: raid level may only be set once. "
+ fprintf(stderr, Name ": raid level may only be set once. "
"Second value is %s.\n", optarg);
exit(2);
}
- if (strcmp(optarg,"linear")==0)
- level = -1;
- else if (strlen(optarg)==1 && strchr("01245", optarg[0]))
- level = optarg[0]-'0';
- else {
- fprintf(stderr, "mdctl: invalid raid level: %s\n",
+ level = map_name(pers, optarg);
+ if (level == -10) {
+ fprintf(stderr, Name ": invalid raid level: %s\n",
optarg);
exit(2);
}
if (level > 0 && mode == 'B') {
- fprintf(stderr, "mdctl: Raid level %s not permitted with --build.\n",
- optarg);
- exit(2);
- }
- if (layout >=0 && level < 4) {
- fprintf(stderr, "mdctl: raid level %s is incompatible with layout setting\n",
+ fprintf(stderr, Name ": Raid level %s not permitted with --build.\n",
optarg);
exit(2);
}
if (sparedisks > 0 && level < 1) {
- fprintf(stderr, "mdctl: raid level %s is incompatible with spare-disks setting.\n",
+ fprintf(stderr, Name ": raid level %s is incompatible with spare-disks setting.\n",
optarg);
exit(2);
}
case O('C','p'): /* raid5 layout */
if (layout >= 0) {
- fprintf(stderr,"mdctl: layout may only be sent once. "
+ fprintf(stderr,Name ": layout may only be sent once. "
"Second value was %s\n", optarg);
exit(2);
}
- if (level > -10 && level < 4) {
- fprintf(stderr,"mdctl: layout is incompatible with raid levels below 4.\n");
- exit(2);
- }
- if (strcmp(optarg, "left-symmetric")==0 || strcmp(optarg,"ls")==0)
- layout = ALGORITHM_LEFT_SYMMETRIC;
- else if (strcmp(optarg, "left-asymmetric")==0 || strcmp(optarg,"la")==0)
- layout = ALGORITHM_LEFT_ASYMMETRIC;
- else if (strcmp(optarg, "right-symmetric")==0 || strcmp(optarg,"rs")==0)
- layout = ALGORITHM_RIGHT_SYMMETRIC;
- else if (strcmp(optarg, "right-asymmetric")==0 || strcmp(optarg,"ra")==0)
- layout = ALGORITHM_RIGHT_ASYMMETRIC;
- else {
- fprintf(stderr,"mdctl: %s is not a valid layout value\n",
- optarg);
- exit(2);
+ switch(level) {
+ default:
+ fprintf(stderr, Name ": layout now meaningful for %s arrays.\n",
+ map_num(pers, level));
+ exit(2);
+ case -10:
+ fprintf(stderr, Name ": raid level must be given before layout.\n");
+ exit(2);
+
+ case 5:
+ layout = map_name(r5layout, optarg);
+ if (layout==-10) {
+ fprintf(stderr, Name ": layout %s not understood for raid5.\n",
+ optarg);
+ exit(2);
+ }
+ break;
}
continue;
case O('C','n'):
case O('B','n'): /* number of raid disks */
if (raiddisks) {
- fprintf(stderr, "mdctl: raid-disks set twice: %d and %s\n",
+ fprintf(stderr, Name ": raid-disks set twice: %d and %s\n",
raiddisks, optarg);
exit(2);
}
raiddisks = strtol(optarg, &c, 10);
if (!optarg[0] || *c || raiddisks<=0 || raiddisks > MD_SB_DISKS) {
- fprintf(stderr, "mdctl: invalid number of raid disks: %s\n",
+ fprintf(stderr, Name ": invalid number of raid disks: %s\n",
optarg);
exit(2);
}
case O('C','x'): /* number of spare (eXtra) discs */
if (sparedisks) {
- fprintf(stderr,"mdctl: spare-disks set twice: %d and %s\n",
+ fprintf(stderr,Name ": spare-disks set twice: %d and %s\n",
sparedisks, optarg);
exit(2);
}
if (level > -10 && level < 1) {
- fprintf(stderr, "mdctl: spare-disks setting is incompatible with raid level %d\n",
+ fprintf(stderr, Name ": spare-disks setting is incompatible with raid level %d\n",
level);
exit(2);
}
sparedisks = strtol(optarg, &c, 10);
if (!optarg[0] || *c || sparedisks < 0 || sparedisks > MD_SB_DISKS - raiddisks) {
- fprintf(stderr, "mdctl: invalid number of spare disks: %s\n",
+ fprintf(stderr, Name ": invalid number of spare disks: %s\n",
optarg);
exit(2);
}
continue;
case O('A','u'): /* uuid of array */
if (uuidset) {
- fprintf(stderr, "mdctl: uuid cannot bet set twice. "
+ fprintf(stderr, Name ": uuid cannot bet set twice. "
"Second value %s.\n", optarg);
exit(2);
}
if (parse_uuid(optarg, uuid))
uuidset = 1;
else {
- fprintf(stderr,"mdctl: Bad uuid: %s\n", optarg);
+ fprintf(stderr,Name ": Bad uuid: %s\n", optarg);
exit(2);
}
continue;
case O('A','c'): /* config file */
if (configfile) {
- fprintf(stderr, "mdctl: configfile cannot be set twice. "
+ fprintf(stderr, Name ": configfile cannot be set twice. "
"Second value is %s.\n", optarg);
exit(2);
}
case O('B','R'):
case O('C','R'): /* Run the array */
if (runstop < 0) {
- fprintf(stderr, "mdctl: Cannot both Stop and Run an array\n");
+ fprintf(stderr, Name ": Cannot both Stop and Run an array\n");
exit(2);
}
runstop = 1;
continue;
case O('@','S'):
if (runstop > 0) {
- fprintf(stderr, "mdctl: Cannot both Run and Stop an array\n");
+ fprintf(stderr, Name ": Cannot both Run and Stop an array\n");
exit(2);
}
runstop = -1;
case O('@','o'):
if (readonly < 0) {
- fprintf(stderr, "mdctl: Cannot have both readonly and readwrite\n");
+ fprintf(stderr, Name ": Cannot have both readonly and readwrite\n");
exit(2);
}
readonly = 1;
/* We have now processed all the valid options. Anything else is
* an error
*/
- fprintf(stderr, "mdctl: option %c not valid in mode %c\n",
+ fprintf(stderr, Name ": option %c not valid in mode %c\n",
opt, mode);
exit(2);
*/
if (mode !='D' && mode !='E' && ! (mode =='A' && scan)) {
if (!mddev) {
- fprintf(stderr, "mdctl: an md device must be given in this mode\n");
+ fprintf(stderr, Name ": an md device must be given in this mode\n");
exit(2);
}
mdfd = open(mddev, O_RDWR, 0);
if (mdfd < 0) {
- fprintf(stderr,"mdctl: error opening %s: %s\n",
+ fprintf(stderr,Name ": error opening %s: %s\n",
mddev, strerror(errno));
exit(1);
}
if (md_get_version(mdfd) <= 0) {
- fprintf(stderr, "mdctl: %s does not appear to be an md device\n",
+ fprintf(stderr, Name ": %s does not appear to be an md device\n",
mddev);
close(mdfd);
exit(1);
rv = Build(mddev, mdfd, chunk, level, raiddisks, subdevs,subdev);
break;
case 'C': /* Create */
- rv = Create(mddev, mdfd, chunk, level, layout, raiddisks, sparedisks,
- subdevs,subdev,runstop);
+ rv = Create(mddev, mdfd, chunk, level, layout, size, raiddisks, sparedisks,
+ subdevs,subdev,runstop, verbose);
break;
case 'D': /* Detail */
for (i=0; i<subdevs; i++)
#include "md_u.h"
+#define Name "mdctl"
+
extern char short_options[];
extern struct option long_options[];
extern char Version[], Usage[], Help[], Help_create[], Help_build[], Help_assemble[];
struct mddev_dev_s *next;
} *mddev_dev_t;
-/*
- * RAID5 supported algorithms
- */
-#define ALGORITHM_LEFT_ASYMMETRIC 0
-#define ALGORITHM_RIGHT_ASYMMETRIC 1
-#define ALGORITHM_LEFT_SYMMETRIC 2
-#define ALGORITHM_RIGHT_SYMMETRIC 3
+typedef struct mapping {
+ char *name;
+ int num;
+} mapping_t;
+
+extern char *map_num(mapping_t *map, int num);
+extern int map_name(mapping_t *map, char *name);
+extern mapping_t r5layout[], pers[];
+
extern int Manage_ro(char *devname, int fd, int readonly);
extern int Create(char *mddev, int mdfd,
- int chunk, int level, int layout, int raiddisks, int sparedisks,
+ int chunk, int level, int layout, int size, int raiddisks, int sparedisks,
int subdevs, char *subdev[],
- int runstop);
+ int runstop, int verbose);
extern int Detail(char *dev);
extern int Examine(char *dev);
extern int md_get_version(int fd);
extern int get_linux_version();
extern int parse_uuid(char *str, int uuid[4]);
+extern int check_ext2(int fd, char *name);
+extern int check_reiser(int fd, char *name);
+extern int check_raid(int fd, char *name);
extern mddev_uuid_t conf_get_uuids(char *);
extern mddev_dev_t conf_get_devs(char *);
return -1;
if (ioctl(fd, RAID_VERSION, &vers) == 0)
- return (vers.major<<16) | (vers.minor<<8) | vers.patchlevel;
+ return (vers.major*10000) + (vers.minor*100) + vers.patchlevel;
if (MAJOR(stb.st_rdev) == MD_MAJOR)
- return (36<<8);
+ return (3600);
return -1;
}
if (sscanf(name.release, "%d.%d.%d", &a,&b,&c)!= 3)
return -1;
- return (a<<16)+(b<<8)+c;
+ return (a*1000000)+(b*1000)+c;
}
int enough(int level, int raid_disks, int avail_disks)
if (lseek64(fd, offset, 0)< 0LL)
return 3;
- if (read(fd, &super, sizeof(super)) != sizeof(super))
+ if (read(fd, super, sizeof(*super)) != sizeof(*super))
return 4;
if (super->md_magic != MD_SB_MAGIC)
return 0;
}
+
+int check_ext2(int fd, char *name)
+{
+ /*
+ * Check for an ext2fs file system.
+ * Superblock is always 1K at 1K offset
+ *
+ * s_magic is le16 at 56 == 0xEF53
+ * report mtime - le32 at 44
+ * blocks - le32 at 4
+ * logblksize - le32 at 24
+ */
+ unsigned char sb[1024];
+ time_t mtime;
+ int size, bsize;
+ if (lseek(fd, 1024,0)!= 1024)
+ return 0;
+ if (read(fd, sb, 1024)!= 1024)
+ return 0;
+ if (sb[56] != 0x53 || sb[57] != 0xef)
+ return 0;
+
+ mtime = sb[44]|(sb[45]|(sb[46]|sb[47]<<8)<<8)<<8;
+ bsize = sb[24]|(sb[25]|(sb[26]|sb[27]<<8)<<8)<<8;
+ size = sb[4]|(sb[5]|(sb[6]|sb[7]<<8)<<8)<<8;
+ fprintf(stderr, Name ": %s appears to contain an ext2fs file system\n",
+ name);
+ fprintf(stderr," size=%dK mtime=%s",
+ size*(1<<bsize), ctime(&mtime));
+ return 1;
+}
+
+int check_reiser(int fd, char *name)
+{
+ /*
+ * superblock is at 64K
+ * size is 1024;
+ * Magic string "ReIsErFs" or "ReIsEr2Fs" at 52
+ *
+ */
+ unsigned char sb[1024];
+ int size;
+ if (lseek(fd, 64*1024, 0) != 64*1024)
+ return 0;
+ if (read(fd, sb, 1024) != 1024)
+ return 0;
+ if (strncmp(sb+52, "ReIsErFs",8)!=0 &&
+ strncmp(sb+52, "ReIsEr2Fs",9)!=0)
+ return 0;
+ fprintf(stderr, Name ": %s appears to contain a reiserfs file system\n",name);
+ size = sb[0]|(sb[1]|(sb[2]|sb[3]<<8)<<8)<<8;
+ fprintf(stderr, " size = %dK\n", size*4);
+
+ return 1;
+}
+
+int check_raid(int fd, char *name)
+{
+ mdp_super_t super;
+ time_t crtime;
+ 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",
+ name);
+ crtime = super.ctime;
+ fprintf(stderr, " level=%d disks=%d ctime=%s",
+ super.level, super.raid_disks, ctime(&crtime));
+ return 1;
+}
+
+
+int ask(char *mesg)
+{
+ char *add = "";
+ int i;
+ for (i=0; i<5; i++) {
+ char buf[100];
+ fprintf(stderr, "%s%s", mesg, add);
+ fflush(stderr);
+ if (fgets(buf, 100, stdin)==NULL)
+ return 0;
+ if (buf[0]=='y' || buf[0]=='Y')
+ return 1;
+ if (buf[0]=='n' || buf[0]=='N')
+ return 0;
+ add = "(y/n) ";
+ }
+ fprintf(stderr, Name ": assuming 'no'\n");
+ return 0;
+}
+
+char *map_num(mapping_t *map, int num)
+{
+ while (map->name) {
+ if (map->num == num)
+ return map->name;
+ map++;
+ }
+ return NULL;
+}
+
+int map_name(mapping_t *map, char *name)
+{
+ while (map->name) {
+ if (strcmp(map->name, name)==0)
+ return map->num;
+ map++;
+ }
+ return -10;
+}