1 /* geometry.c - Device and file geometry computation */
3 Copyright 1992-1998 Werner Almesberger.
4 Copyright 1999-2005 John Coffman.
7 Licensed under the terms contained in the file 'COPYING' in the
11 /* Patched for linux-2.4.0 - Glibc-2.2 by Sergey Ostrovsky 11/16/2000 */
21 #include <sys/types.h>
24 #include <sys/statfs.h>
27 #define _I386_STATFS_H /* two versions of statfs is not good ... */
36 # include <libdevmapper.h>
48 #ifndef REISERFS_SUPER_MAGIC
49 #define REISERFS_SUPER_MAGIC 0x52654973
53 #ifndef REISERFS_SUPER_MAGIC_STRING
54 #define REISERFS_SUPER_MAGIC_STRING "ReIsErFs"
58 #ifndef REISERFS_IOC_UNPACK
59 #define REISERFS_IOC_UNPACK _IOW(0xCD,1,long)
62 #ifndef REISER4_SUPER_MAGIC
63 #define REISER4_SUPER_MAGIC 0x52345362
64 /* (*(__u32 *)"R4Sb"); */
66 #ifndef REISER4_IOC_UNPACK
67 #define REISER4_IOC_UNPACK _IOW(0xCD,1,long)
72 typedef struct _dm_target {
73 struct _dm_target *next;
74 uint64_t start,length,offset;
78 typedef struct _dm_table {
79 struct _dm_table *next;
81 struct _dm_target *target;
84 DM_TABLE *dmtab = NULL;
85 int dm_version_nr = 0;
88 int dm_major_list[16];
94 dev_t lv_dev; /* was __u16, which is wrong */
98 /* Should the definition be: */
99 #define LV_BMAP _IOWR(0xfe, 0x30, int)
100 /* As defined in the 2.4 kernels: */
101 /*#define LV_BMAP _IOWR(0xfe, 0x30, 1) */
103 #ifndef LVM_GET_IOP_VERSION
104 /* Should the definition be: */
105 #define LVM_GET_IOP_VERSION _IOR(0xfe, 0x98, unsigned short)
106 /* As defined in the 2.4 kernels: */
107 /*#define LVM_GET_IOP_VERSION _IOR(0xfe, 0x98, 1) */
112 struct evms_get_bmap_t {
118 struct evms_version_t {
124 #ifndef EVMS_GET_BMAP
125 #define EVMS_GET_BMAP _IOWR(MAJOR_EVMS, 0xC7, struct evms_get_bmap_t)
127 #ifndef EVMS_GET_IOCTL_VERSION
128 #define EVMS_GET_IOCTL_VERSION _IOR(MAJOR_EVMS, 0x0, struct evms_version_t)
133 #define HDIO_GETGEO HDIO_REQ
137 typedef struct _st_buf {
138 struct _st_buf *next;
143 DT_ENTRY *disktab = NULL;
147 void geo_init(char *name)
150 char line[MAX_LINE+1];
159 int disk_section,items;
162 if ((file = fopen(name,"r")) == NULL)
163 die("open %s: %s",name,strerror(errno));
165 if (name || (file = fopen(DFL_DISKTAB,"r")) != NULL) {
166 disk_section = !!disktab;
167 while (fgets(line,MAX_LINE,file)) {
168 here = strchr(line,'\n');
170 here = strchr(line,'#');
172 if (strspn(line," \t") != strlen(line)) {
173 entry = alloc_t(DT_ENTRY);
174 items = sscanf(line,"0x%x 0x%x %d %d %d %d",&entry->device,
175 (unsigned int*)&entry->bios,&entry->sectors,&entry->heads,&entry->cylinders,
177 if (items == 5) entry->start = -1;
179 die("Invalid line in %s:\n\"%s\"",name ? name : DFL_DISKTAB,
181 entry->next = disktab;
183 if (disk_section) die("DISKTAB and DISK are mutually exclusive");
191 file = fopen("/proc/devices", "r");
195 if (!fgets(line, (sizeof line)-1, file)) {
199 line[(sizeof line)-1] = 0;
200 } while(strncmp(line, "Block", 5) != 0);
202 while(fgets(line, (sizeof line)-1, file)) {
203 if (sscanf(line, "%d %31s\n", &major, major_name) != 2) continue;
204 if (strcmp(major_name, "device-mapper") != 0) continue;
205 dm_major_list[dm_major_nr] = major;
207 printf("device-mapper major = %d\n", major);
209 if (++dm_major_nr > nelem(dm_major_list) ) break;
216 /* Suppress error message if the device doesn't exist. It is ugly */
219 if (stat ("/dev/mapper/control", &fs))
222 if (!(dmt = dm_task_create(DM_DEVICE_VERSION)))
224 if (!dm_task_run(dmt))
226 if (!dm_task_get_driver_version(dmt, dm_version, sizeof dm_version))
230 * to not confuse returned device number formats %02x:%02x and %d:%d
231 * we assume here that the %02x:%02x format is only found in the ioctl
232 * interface version < 4 (this is really getting ugly...)
234 dm_version_nr = atoi(dm_version);
236 dm_task_destroy(dmt);
241 int is_dm_major(int major)
245 for(i=0; i<dm_major_nr; i++) {
246 if (dm_major_list[i] == major) return 1;
253 void do_partition(void)
255 DT_ENTRY *entry,*walk;
257 char *partition,*start;
259 entry = alloc_t(DT_ENTRY);
262 partition = cfg_get_strg(cf_partitions,"partition");
263 if (stat(partition,&st) < 0) die("stat %s: %s",partition,strerror(errno));
264 if (!S_ISBLK(st.st_mode) || ((st.st_rdev ^ disktab->device) & D_MASK(st.st_rdev)))
265 die("%s is not a valid partition device",partition);
266 entry->device = st.st_rdev;
267 cfg_init(cf_partition);
268 (void) cfg_parse(cf_partition);
269 start = cfg_get_strg(cf_partition,"start");
270 entry->start = start ? to_number(start) : -1;
271 for (walk = disktab; walk; walk = walk->next)
272 if (entry->device == walk->device)
273 die("Duplicate geometry definition for %s",partition);
274 entry->next = disktab;
276 cfg_init(cf_partitions);
280 int has_partitions_beta(dev_t dev)
282 int major = MAJOR(dev);
285 major == MAJOR_HD || major == MAJOR_IDE2 ||
286 major == MAJOR_IDE3 || major == MAJOR_IDE4 ||
287 major == MAJOR_IDE5 || major == MAJOR_IDE6 ||
288 major == MAJOR_EMD ||
289 (major >= MAJOR_IDE7 && major <= MAJOR_IDE10) ||
290 major == MAJOR_XT || major == MAJOR_ESDI || major == MAJOR_ACORN
291 ) return 0xFFFFFFC0; /* 6 bit partition mask */
294 major == MAJOR_SD || (major >= MAJOR_SD2 && major <= MAJOR_SD8) ||
295 major == MAJOR_AMI_HYP || major == MAJOR_HPT370 ||
296 (major >= MAJOR_EXPR && major <= MAJOR_EXPR+3) ||
297 (major >= MAJOR_I2O && major <= MAJOR_I2O+7) ||
298 (major >= MAJOR_SMART2 && major <= MAJOR_SMART2+7) ||
299 (major >= MAJOR_CISS && major <= MAJOR_CISS+7) ||
300 major == MAJOR_FTL || major == MAJOR_NFTL || major == MAJOR_DOC ||
301 (major >= MAJOR_SD9 && major <= MAJOR_SD16)
302 ) return 0xFFFFFFF0; /* 4 bit partition mask */
304 if ( major == MAJOR_SATA || major == MAJOR_SATA2
305 ) return 0xFFFFFFE0; /* 5 bit partition mask */
307 if ( major == MAJOR_IBM_iSER ||
308 (major >= MAJOR_DAC960 && major <= MAJOR_DAC960+7) ||
309 (major >= MAJOR_DAC960_8 && major <= MAJOR_DAC960_8+7)
310 ) return 0xFFFFFFF8; /* 3 bit partition mask */
317 unsigned char max_partno[512] = {
319 0 1 2 3 4 5 6 7 8 9 A B C D E F
321 0, 0, 0, 63, 0, 0, 0, 0, 15, 0, 0, 0, 0, 63, 0, 0, /* 0x */
322 0, 0, 0, 0, 0, 63, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0,
323 0, 63, 63, 0, 63, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0,
325 7, 7, 7, 7, 7, 7, 7, 7, 0, 63, 0, 0, 15, 15, 15, 15,
327 7, 7, 7, 7, 7, 7, 7, 7, 63, 63, 0, 0, 15, 15, 15, 15,
330 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, /* 4x */
331 15, 15, 15, 15, 15, 15, 15, 15, 63, 63, 63, 63, 0, 15, 0, 0,
332 0, 0, 0, 0, 15, 15, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15,
333 7, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
335 0 1 2 3 4 5 6 7 8 9 A B C D E F
337 15, 15, 15, 15, 15, 15, 15, 15, 7, 7, 7, 7, 7, 7, 7, 7, /* 8x */
338 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0,
339 31, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
340 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
342 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Cx */
343 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
344 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
345 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
347 0 1 2 3 4 5 6 7 8 9 A B C D E F
351 int has_partitions(dev_t dev)
353 int major = MAJOR(dev);
356 if (major >= nelem(max_partno)) {
357 warn("Major Device (%d) > %d",
358 major, nelem(max_partno)-1);
360 else if ( (ret=max_partno[major]) ) ret ^= 0xFFFFFFFF;
368 DT_ENTRY *entry,*walk;
370 char *disk,*bios,*sectors,*heads,*cylinders,*maxpart;
373 disk = cfg_get_strg(cf_options,"disk");
375 (void) cfg_parse(cf_disk);
376 if (stat(disk,&st) < 0) {
377 if (cfg_get_flag(cf_disk,"inaccessible")) {
378 cfg_unset(cf_options,"disk");
381 die("do_disk: stat %s: %s",disk,strerror(errno));
383 if (!S_ISBLK(st.st_mode) ||
384 (has_partitions(st.st_rdev) && (MINOR(st.st_rdev) & P_MASK(st.st_rdev))))
385 die(" '%s' is not a whole disk device",disk);
387 entry = alloc_t(DT_ENTRY);
388 entry->device = st.st_rdev;
389 major = MAJOR(st.st_rdev);
390 bios = cfg_get_strg(cf_disk,"bios");
391 sectors = cfg_get_strg(cf_disk,"sectors");
392 heads = cfg_get_strg(cf_disk,"heads");
393 cylinders = cfg_get_strg(cf_disk,"cylinders");
394 maxpart = cfg_get_strg(cf_disk,"max-partitions");
396 if (major<nelem(max_partno)) {
397 int i = to_number(maxpart);
398 if (max_partno[major] && max_partno[major]!=i) die("Cannot alter 'max-partitions' for known disk %s", disk);
399 max_partno[major] = i;
400 if (i!=7 && i!=15 && i!=31 && i!=63) die("disk=%s: illegal value for max-partitions(%d)", disk, i);
403 die("Implementation restriction: max-partitions on major device > %d", (int)nelem(max_partno)-1);
406 entry->bios = bios ? to_number(bios) : -1;
407 if (!sectors && !heads) entry->sectors = entry->heads = -1;
408 else if (!(sectors && heads))
409 die("Must specify SECTORS and HEADS together");
411 entry->sectors = to_number(sectors);
412 entry->heads = to_number(heads);
414 if (cfg_get_flag(cf_disk,"inaccessible")) {
416 if (bios) die("INACCESSIBLE and BIOS are mutually exclusive");
417 if ( sectors || heads || cylinders )
418 die("No geometry variables allowed if INACCESSIBLE");
420 entry->cylinders = cylinders ? to_number(cylinders) : -1;
422 for (walk = disktab; walk; walk = walk->next) {
423 if (entry->device == walk->device)
424 die("Duplicate \"disk =\" definition for %s",disk);
426 entry->next = disktab;
429 printf("do_disk: %s %04X 0x%02X %d:%d:%d\n",
430 disk, entry->device, entry->bios, entry->cylinders,
431 entry->heads, entry->sectors);
433 cfg_init(cf_partitions);
434 (void) cfg_parse(cf_partitions);
435 cfg_unset(cf_options,"disk");
439 static int exists(const char *name)
441 struct hd_geometry dummy;
445 if ((fd = open(name,O_RDWR)) < 0) return 0; /* was O_RDONLY */
446 yes = read(fd,&buff,1) == 1 && ioctl(fd,HDIO_GETGEO,&dummy) >= 0;
454 static int scan_last_dev(ST_BUF *next,char *parent,int major,int increment)
458 char name[PATH_MAX+1];
464 if ((dp = opendir(parent)) == NULL)
465 die("opendir %s: %s",parent,strerror(errno));
466 while ((dir = readdir(dp))) {
467 sprintf(name,"%s/%s",parent,dir->d_name);
468 if (stat(name,&st.st) >= 0) {
469 if (S_ISBLK(st.st.st_mode) && MAJOR(st.st.st_rdev) == major &&
470 (MINOR(st.st.st_rdev) & (increment-1)) == 0) {
471 this = MINOR(st.st.st_rdev)/increment+1;
472 if (this > max && exists(name)) max = this;
474 if (S_ISDIR(st.st.st_mode) && strcmp(dir->d_name,".") &&
475 strcmp(dir->d_name,"..")) {
476 for (walk = next; walk; walk = walk->next)
477 if (stat_equal(&walk->st,&st.st)) break;
479 this = scan_last_dev(&st,name,major,increment);
480 if (this > max) max = this;
492 static int last_dev(int major,int increment)
495 * In version 12 to 18, LILO only relied on scan_last_dev (or last_dev). This
496 * obviously didn't work if entries in /dev were missing. Versions 18 and 19
497 * added the probe loop, which seems to be okay, but which may probe for
498 * invalid minor numbers. The IDE driver objects to that. Since last_dev is
499 * only used to count IDE drives anyway, we try now only the first two devices
500 * and forget about scan_last_dev.
504 static int cached_major=-1, cached_increment=-1, cached_result=-1;
505 if(major == cached_major && increment == cached_increment)
506 return cached_result;
507 cached_major = major;
508 cached_increment = increment;
512 devs < 2 && dev_open(&dev,MKDEV(major,increment*devs),O_BYPASS);
514 if (exists(dev.name)) dev_close(&dev);
519 cached_result = devs;
525 void lvm_bmap(struct lv_bmap *lbm)
528 static int lvmfd = -1;
529 static dev_t last_dev = 0;
531 if (lbm->lv_dev != last_dev) {
532 char lvm_char[] = DEV_DIR "/lvm";
538 if ((lvmfd = open(lvm_char, lbm->lv_dev, O_RDONLY)) < 0)
539 die("can't open LVM char device %s\n", lvm_char);
541 if (ioctl(lvmfd, LVM_GET_IOP_VERSION, &iop) < 0)
542 die("LVM_GET_IOP_VERSION failed on %s\n", lvm_char);
545 die("LVM IOP %d not supported for booting\n", iop);
548 lvmfd = dev_open(&dev, lbm->lv_dev, O_RDONLY);
550 die("can't open LVM block device %#x\n", (int)lbm->lv_dev);
551 last_dev = lbm->lv_dev;
553 if (ioctl(lvmfd, LV_BMAP, lbm) < 0) {
554 perror(__FUNCTION__);
555 pdie("LV_BMAP error or ioctl unsupported, can't have image in LVM.\n");
562 void evms_bmap(struct evms_get_bmap_t *ebm)
565 static int evms_fd = -1;
566 static dev_t evms_last_dev = 0;
568 if (ebm->dev != evms_last_dev) {
569 char evms_blk[] = DEV_DIR "/evms/block_device";
570 struct evms_version_t evms_ver;
572 /* Open the EVMS device */
576 evms_fd = open(evms_blk, O_RDONLY);
578 die("Can't open EVMS block device %s.\n", evms_blk);
580 /* Get EVMS ioctl version number. */
581 if (ioctl(evms_fd, EVMS_GET_IOCTL_VERSION, &evms_ver) < 0)
582 die("EVMS_GET_IOCTL_VERSION failed on %s.\n", evms_blk);
584 /* Check that the ioctl version is >= 7.1.0 */
585 if (evms_ver.major < 7 ||
586 (evms_ver.major == 7 && evms_ver.minor < 1))
587 die("EVMS ioctl version %d.%d.%d does not support booting.\n",
588 evms_ver.major, evms_ver.minor, evms_ver.patch);
591 evms_fd = dev_open(&dev, ebm->dev, O_RDONLY);
593 die("Can't open EVMS block device %#x\n", ebm->dev);
594 evms_last_dev = ebm->dev;
597 if (ioctl(evms_fd, EVMS_GET_BMAP, ebm) < 0) {
598 perror(__FUNCTION__);
599 pdie("EVMS_GET_BMAP error or ioctl unsupported. Can't have image on EVMS volume.\n");
605 void geo_query_dev(GEOMETRY *geo,int device,int all)
608 int fd,get_all,major;
609 struct floppy_struct fdprm;
610 struct hd_geometry hdprm;
612 if (verbose>=5) printf("geo_query_dev: device=%04X\n", device);
614 /* Werner's original */
615 get_all = all || MAJOR(device) != MAJOR_FD; */
617 /* simplify the condition -- JRC 2003-06-04 */
621 die("Trying to map files from unnamed device 0x%04x (NFS/RAID mirror down ?)",device);
622 if (device == MAJMIN_RAM)
623 die("Trying to map files from your RAM disk. "
624 "Please check -r option or ROOT environment variable.");
626 fd = dev_open(&dev,device,O_NOACCESS);
629 fd = -1; /* pacify GCC */
630 geo->heads = geo->cylinders = geo->sectors = 1;
634 switch ((major=MAJOR(device))) {
636 geo->device = device & 3;
638 if (ioctl(fd,FDGETPRM,&fdprm) < 0)
639 die("geo_query_dev FDGETPRM (dev 0x%04x): %s",device,
641 geo->heads = fdprm.head;
642 geo->cylinders = fdprm.track;
643 geo->sectors = fdprm.sect;
662 geo->device = 0x80 + (MINOR(device) >> 6) +
663 (MAJOR(device) == MAJOR_HD ? 0 : last_dev(MAJOR_HD,64));
665 if (ioctl(fd,HDIO_GETGEO,&hdprm) < 0)
666 die("geo_query_dev HDIO_GETGEO (dev 0x%04x): %s",device,
668 geo->heads = hdprm.heads;
669 geo->cylinders = hdprm.cylinders;
670 geo->sectors = hdprm.sectors;
671 geo->start = hdprm.start;
682 geo->device = 0x80 + last_dev(MAJOR_HD,64) + (MINOR(device) >> 4);
684 if (ioctl(fd,HDIO_GETGEO,&hdprm) < 0)
685 die("geo_query_dev HDIO_GETGEO (dev 0x%04x): %s",device,
687 if (all && !hdprm.sectors)
688 die("HDIO_REQ not supported for your SCSI controller. Please "
689 "use a DISK section");
690 geo->heads = hdprm.heads;
691 geo->cylinders = hdprm.cylinders;
692 geo->sectors = hdprm.sectors;
693 geo->start = hdprm.start;
696 geo->device = 0x80 + last_dev(MAJOR_HD,64) + (MINOR(device) >> 5);
698 if (ioctl(fd,HDIO_GETGEO,&hdprm) < 0)
699 die("geo_query_dev HDIO_GETGEO (dev 0x%04x): %s",device,
701 if (all && !hdprm.sectors)
702 die("HDIO_REQ not supported for your Disk controller. Please "
703 "use a DISK section");
704 geo->heads = hdprm.heads;
705 geo->cylinders = hdprm.cylinders;
706 geo->sectors = hdprm.sectors;
707 geo->start = hdprm.start;
719 geo->device = 0x80 + last_dev(MAJOR_HD,64) + (MINOR(device) >> 3);
721 if (ioctl(fd,HDIO_GETGEO,&hdprm) < 0)
722 die("geo_query_dev HDIO_GETGEO (dev 0x%04x): %s",device,
724 if (all && !hdprm.sectors)
725 die("HDIO_REQ not supported for your DAC960/IBM controller. "
726 "Please use a DISK section");
727 geo->heads = hdprm.heads;
728 geo->cylinders = hdprm.cylinders;
729 geo->sectors = hdprm.sectors;
730 geo->start = hdprm.start;
765 geo->device = 0x80 + last_dev(MAJOR_HD,64) + (MINOR(device) >> 4);
767 if (ioctl(fd,HDIO_GETGEO,&hdprm) < 0)
768 die("geo_query_dev HDIO_GETGEO (dev 0x%04x): %s",device,
770 if (all && !hdprm.sectors)
771 die("HDIO_REQ not supported for your Array controller. Please "
772 "use a DISK section");
773 geo->heads = hdprm.heads;
774 geo->cylinders = hdprm.cylinders;
775 geo->sectors = hdprm.sectors;
776 geo->start = hdprm.start;
780 if (max_partno[major] && major==MAJOR_LOOP) break;
781 if (max_partno[major] == 63) goto MASK63;
782 if (max_partno[major] == 31) goto MASK31;
783 if (max_partno[major] == 15) goto MASK15;
784 if (max_partno[major] == 7) goto MASK7;
786 if ((MAJOR(device)>=120 && MAJOR(device)<=127) ||
787 (MAJOR(device)>=240 && MAJOR(device)<=254) )
788 die("Linux experimental device 0x%04x needs to be defined.\n"
789 "Check 'man lilo.conf' under 'disk=' and 'max-partitions='", device);
790 else die("Sorry, don't know how to handle device 0x%04x",device);
792 if (get_all) dev_close(&dev);
793 if (verbose>=5) printf("exit geo_query_dev\n");
797 int is_first(int device)
801 for (walk = disktab; walk; walk = walk->next)
802 if (walk->device == device) break;
803 if (!walk && !old_disktab)
804 for (walk = disktab; walk; walk = walk->next)
805 if (walk->device == (device & D_MASK(device))) break;
806 if (walk && !walk->heads)
807 die("Device 0x%04X: Configured as inaccessible.\n",device);
808 if (walk && walk->bios != -1) return !(walk->bios & 0x7f);
809 switch (MAJOR(device)) {
811 return !(device & 3);
814 return !(MINOR(device) >> 6);
829 return MINOR(device) >> 6 ? 0 : !last_dev(MAJOR_HD,64);
871 return MINOR(device) >> 4 ? 0 : !last_dev(MAJOR_HD,64);
882 return MINOR(device) >> 3 ? 0 : !last_dev(MAJOR_HD,64);
885 return 1; /* user knows what (s)he's doing ... I hope */
890 void geo_get(GEOMETRY *geo,int device,int user_device,int all)
893 int inherited,keep_cyls,is_raid=0;
897 for(i = 0; i < dm_major_nr; i++)
898 if (MAJOR(device) == dm_major_list[i])
900 while (i < dm_major_nr) {
903 for(dm_table = dmtab; dm_table; dm_table = dm_table->next)
904 if (dm_table->device == device)
911 for(target = dm_table->target; target; target = target->next)
912 device = target->device;
917 char dmdev[PATH_MAX+1];
918 char buf[PATH_MAX+1];
922 dev_open(&dev, device, -1);
923 strncpy(dmdev, dev.name, PATH_MAX);
926 memset(buf, 0, PATH_MAX + 1);
927 if ((result = readlink(dmdev, buf, PATH_MAX)) < 0 && errno != EINVAL)
928 die("device-mapper: readlink(\"%s\") failed with: %s",buf,
931 if (buf[0] != '/' && (slash = strrchr(dmdev, '/')) != NULL)
935 strncpy(slash, buf, PATH_MAX - (slash-dmdev));
937 if (realpath(dmdev, buf) == NULL)
938 die("device-mapper: realpath(\"%s\") failed with: %s",dmdev,
940 strncpy(dmdev, buf, PATH_MAX);
941 } while (result >= 0);
944 if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
945 die("device-mapper: dm_task_create(DM_DEVICE_TABLE) failed");
946 slash = strrchr(dmdev, '/');
951 if (!dm_task_set_major(dmt, MAJOR(device)) ||
952 !dm_task_set_minor(dmt, MINOR(device)))
953 die("device-mapper: dm_task_set_major() or dm_task_set_minor() failed");
954 if (!dm_task_run(dmt))
955 die("device-mapper: dm_task_run(DM_DEVICE_TABLE) failed");
957 dm_table = alloc_t(DM_TABLE);
958 dm_table->device = device;
959 dm_table->target = NULL;
960 dm_table->next = dmtab;
967 uint64_t start,length;
969 char *target_type,*params;
972 next = dm_get_next_target(dmt, next, &start, &length,
973 &target_type, ¶ms);
975 if (!target_type) continue;
977 if (strcmp(target_type, "linear") != 0)
978 die("device-mapper: only linear boot device supported");
980 target = alloc_t(DM_TARGET);
981 target->start = start;
982 target->length = length;
983 if (dm_version_nr < 4 &&
984 isxdigit(params[0]) &&
985 isxdigit(params[1]) &&
987 isxdigit(params[3]) &&
988 isxdigit(params[4])) { /* old 2.4 format */
989 if (sscanf(params, "%02x:%02x %"PRIu64, &major, &minor, &target->offset) != 3)
990 die("device-mapper: parse error in linear params (\"%s\")", params);
991 } else if (isdigit(params[0]) &&
992 strchr(params, ':')) { /* dm_bdevname/format_dev_t (>= 2.6.0-test4?) format */
993 if (sscanf(params, "%u:%u %"PRIu64, &major, &minor, &target->offset) != 3)
994 die("device-mapper: parse error in linear params (\"%s\")", params);
995 } else { /* >= 2.5.69 format, this should go away soon */
999 p = strrchr(params, ' ');
1001 die("device-mapper: parse error in linear params (\"%s\")", params);
1003 sprintf(buf, DEV_DIR "/%s", params); /* let's hope it's there */
1004 if (stat(buf, &st) == 0) {
1005 if (!S_ISBLK(st.st_mode))
1006 die("device-mapper: %s is not a valid block device", buf);
1007 major = MAJOR(st.st_rdev);
1008 minor = MINOR(st.st_rdev);
1009 } else { /* let's try sysfs */
1011 sprintf(buf, "/sys/block/%s/dev", params);
1012 file = fopen(buf, "r");
1014 die("device-mapper: \"%s\" could not be opened. /sys mounted?", buf);
1015 if (!fgets(buf, PATH_MAX, file))
1016 die("device-mapper: read error from \"/sys/block/%s/dev\"", params);
1017 if (sscanf(buf, "%u:%u", &major, &minor) != 2) {
1018 if (sscanf(buf, "%x", &dev) != 1)
1019 die("device-mapper: error getting device from \"%s\"", buf);
1023 (void) fclose(file);
1026 if (sscanf(p+1, "%"PRIu64, &target->offset) != 1)
1027 die("device-mapper: parse error in linear params (\"%s\")", params);
1029 target->device = (major << 8) | minor;
1031 device = target->device;
1032 target->next = dm_table->target;
1033 dm_table->target = target;
1036 dm_task_destroy(dmt);
1042 die("device-mapper: Error finding real device");
1043 geo->base_dev = device;
1045 for(i = 0; i < dm_major_nr; i++)
1046 if (MAJOR(device) == dm_major_list[i])
1051 if (verbose>=5) printf("geo_get: device %04X, all=%d\n", device, all);
1054 * Find underlying device (PV) for LVM. It is OK if the underlying PV is
1055 * really an MD RAID1 device, because the geometry of the RAID1 device is
1056 * exactly the same as the underlying disk, so FIBMAP and LV_BMAP should
1057 * return the correct block numbers regardless of MD.
1059 * We do a quick test to see if the LVM LV_BMAP ioctl is working correctly.
1060 * It should map the two blocks with the same difference as they were input,
1061 * with a constant offset from their original block numbers. If this is not
1062 * the case then LV_BMAP is not working correctly (some widely distributed
1063 * kernels did not have working LV_BMAP support, some just oops here).
1065 if (MAJOR(device) == MAJOR_LVM)
1067 struct lv_bmap lbmA, lbmB;
1070 lbmA.lv_dev = lbmB.lv_dev = device;
1072 lbmB.lv_block = DIFF;
1076 if (lbmB.lv_block - lbmA.lv_block != DIFF)
1077 die("This version of LVM does not support boot LVs");
1078 device = geo->base_dev = lbmA.lv_dev;
1083 if (MAJOR(device) == MAJOR_EVMS) {
1084 struct evms_get_bmap_t ebm;
1092 device = geo->base_dev = ebm.dev;
1096 /* Find underlying device for MD RAID */
1097 if (MAJOR(device) == MD_MAJOR) {
1101 struct md_version md_version_info;
1102 md_array_info_t md_array_info;
1103 md_disk_info_t md_disk_info;
1106 sprintf(mdxxx, DEV_DISK_DIR "/md%d", MINOR(device));
1107 if ((md_fd=open(mdxxx,O_NOACCESS)) < 0)
1109 sprintf(mdxxx, DEV_DIR "/md/%d", MINOR(device));
1110 if ((md_fd=open(mdxxx,O_NOACCESS)) < 0)
1111 die("Unable to open %s", mdxxx);
1113 if (ioctl(md_fd,RAID_VERSION,&md_version_info) < 0)
1114 die("Unable to get RAID version on %s", mdxxx);
1115 if (md_version_info.major > 0)
1116 die("Raid major versions > 0 are not supported");
1117 if (md_version_info.minor < 90)
1118 die("Raid versions < 0.90 are not supported");
1120 if (ioctl(md_fd,GET_ARRAY_INFO,&md_array_info) < 0)
1121 die("Unable to get RAID info on %s", mdxxx);
1122 if (md_version_info.major != 0 || md_version_info.minor != 90 ||
1123 ((md_array_info.major_version != 0 ||
1124 md_array_info.minor_version != 90) &&
1125 (md_array_info.major_version != 1 ||
1126 md_array_info.minor_version != 0))
1128 die("Incompatible Raid version information on %s (RV=%d.%d GAI=%d.%d)",
1130 (int)md_version_info.major,
1131 (int)md_version_info.minor,
1132 (int)md_array_info.major_version,
1133 (int)md_array_info.minor_version);
1135 if (md_array_info.level != 1)
1136 die("Only RAID1 devices are supported for boot images");
1137 raid_limit = md_array_info.raid_disks + md_array_info.spare_disks;
1141 is_raid = (device==boot_dev_nr);
1142 md_disk_info.number = raid_index;
1143 if (ioctl(md_fd,GET_DISK_INFO,&md_disk_info) < 0)
1144 die("GET_DISK_INFO: %s", mdxxx);
1145 device = MKDEV(md_disk_info.major, md_disk_info.minor);
1147 #else /* prior to 22.7 */
1150 for (pass = 0; pass < raid_limit; pass++) {
1151 md_disk_info.number = pass;
1152 if (ioctl(md_fd,GET_DISK_INFO,&md_disk_info) < 0)
1155 printf("(raid) GET_DISK_INFO: failed for pass=%d\n", pass);
1159 die("GET_DISK_INFO: %s", mdxxx);
1161 if (!(md_disk_info.state & (1 << MD_DISK_FAULTY))) {
1163 is_raid = (device==boot_dev_nr);
1165 /* this change may be in error; the correct comparison is == */
1166 is_raid = (device!=boot_dev_nr);
1168 device = MKDEV(md_disk_info.major, md_disk_info.minor);
1173 #endif /* end of code prior to version 22.7 */
1179 if (verbose>=5) printf("geo_get(2): device=%04X, all=%d\n", device, all);
1182 /* if using hard disk, scan the devices in /proc/partitions */
1183 if (has_partitions(device) && all) pf_hard_disk_scan();
1188 for (walk = disktab; walk; walk = walk->next)
1189 if (walk->device == device) break;
1190 inherited = !walk && !old_disktab;
1192 if (verbose>=5) printf("inherited=%d\n", inherited);
1195 for (walk = disktab; walk; walk = walk->next)
1196 if (walk->device == (device & D_MASK(device))) break;
1198 if (verbose>=5) printf("walk=%08lx\n", (long)walk);
1202 /* add 'all' to conditional below -- JRC 2002-08-20 */
1203 if (walk && !walk->heads && all)
1205 /* Werner's original conditional */
1206 if (walk && !walk->heads)
1208 die("Device 0x%04X: Configured as inaccessible.\n",device);
1209 keep_cyls = !walk || walk->bios == -1 || walk->heads == -1 ||
1210 walk->sectors == -1 || inherited || walk->start == -1;
1212 if (verbose>=5) printf("inherited=%d keep_cyls=%d\n", inherited, keep_cyls);
1216 /* add 'all' to conditional below -- JRC 2002-08-20 */
1217 if (keep_cyls && (all || MAJOR(device)==MAJOR_FD) ) {
1219 /* Werner's original conditional */
1222 geo_query_dev(geo,device,all);
1224 if (all) bios_device(geo, device);
1226 if ((geo->device & 0x7f) >= bios_max_devs() &&
1227 user_device == -1 && (!walk || walk->bios == -1))
1228 warn("BIOS drive 0x%02x may not be accessible",
1232 if (walk->bios != -1) geo->device = walk->bios;
1233 if (walk->heads != -1) geo->heads = walk->heads;
1234 if (walk->cylinders != -1 || !keep_cyls)
1235 geo->cylinders = walk->cylinders;
1236 if (walk->sectors != -1) geo->sectors = walk->sectors;
1237 if (walk->start != -1 && !inherited) geo->start = walk->start;
1239 if (user_device != -1) geo->device = user_device;
1242 printf("Device 0x%04x: BIOS drive 0x%02x, no geometry.\n",device,
1246 if (!geo->heads || !geo->cylinders || !geo->sectors)
1247 die("Device 0x%04X: Got bad geometry %d/%d/%d\n",device,
1248 geo->sectors,geo->heads,geo->cylinders);
1249 if (geo->heads > BIOS_MAX_HEADS)
1250 die("Device 0x%04X: Maximum number of heads is %d, not %d\n",device,
1251 BIOS_MAX_HEADS,geo->heads);
1252 if (geo->heads == BIOS_MAX_HEADS)
1253 warn("Maximum number of heads = %d (as specified)\n"
1254 " exceeds standard BIOS maximum of 255.", geo->heads);
1255 if (geo->sectors > BIOS_MAX_SECS)
1256 die("Device 0x%04X: Maximum number of sectors is %d, not %d\n",
1257 device,BIOS_MAX_SECS,geo->sectors);
1258 if (geo->sectors == BIOS_MAX_SECS)
1259 warn("Maximum number of heads = %d (as specified)\n"
1260 " exceeds standard BIOS maximum of 63.", geo->sectors);
1262 (geo->start+geo->sectors-1)/geo->heads/geo->sectors >= BIOS_MAX_CYLS
1264 warn("device 0x%04x exceeds %d cylinder limit.\n"
1265 " Use of the 'lba32' option may help on newer (EDD-BIOS) systems.",
1266 device, BIOS_MAX_CYLS);
1269 printf("Device 0x%04x: BIOS drive 0x%02x, %d heads, %d cylinders,\n",
1270 device,geo->device,geo->heads,geo->cylinders == -1 ? BIOS_MAX_CYLS :
1272 printf("%15s%d sectors. Partition offset: %d sectors.\n","",
1273 geo->sectors,geo->start);
1275 geo->raid = is_raid;
1277 /* make the serial number association */
1278 if (!is_raid) register_bios(geo->device, device);
1279 else geo->device = md_bios; /* 22.5.7 add this else */
1282 } /* end of geo_get */
1285 int geo_open(GEOMETRY *geo,const char *name,int flags)
1288 int user_dev,block_size;
1291 if ((here = strrchr(name,':')) == NULL) user_dev = -1;
1294 warn("%s:BIOS syntax is no longer supported.\n Please use a "
1295 "DISK section.", name);
1296 user_dev = to_number(here);
1298 if ((geo->fd = open(name,flags)) < 0)
1299 die("open %s: %s",name,strerror(errno));
1300 if (fstat(geo->fd,&st) < 0) die("fstat %s: %s",name,strerror(errno));
1301 if (!S_ISREG(st.st_mode) && !S_ISBLK(st.st_mode))
1302 die("%s: neither a reg. file nor a block dev.",name);
1303 geo->dev = S_ISREG(st.st_mode) ? st.st_dev : st.st_rdev;
1306 printf("geo_open: (%s) st_dev(file)=%04X st_rdev(blk)=%04X\n",
1313 geo_get(geo, geo->dev, user_dev, 1);
1314 geo->file = S_ISREG(st.st_mode) ? st.st_dev : 0;
1319 if (!geo->file) geo->spb = 2;
1321 if (ioctl(geo->fd,FIGETBSZ,&block_size) < 0) {
1322 warn("FIGETBSZ %s: %s",name,strerror(errno));
1326 if (!block_size || (block_size & (SECTOR_SIZE-1)))
1327 die("Incompatible block size: %d\n",block_size);
1328 geo->spb = block_size/SECTOR_SIZE;
1336 int geo_open_boot(GEOMETRY *geo,char *name)
1340 if (verbose>=5) printf("geo_open_boot: %s\n", name);
1341 if (stat(name,&st) < 0) die("stat %s: %s",name,strerror(errno));
1342 if (!S_ISREG(st.st_mode) && !S_ISBLK(st.st_mode))
1343 die("%s: neither a reg. file nor a block dev.",name);
1344 geo->dev = S_ISREG(st.st_mode) ? st.st_dev : st.st_rdev;
1346 if (MAJOR(geo->dev) == MAJOR_FD) geo->fd = 0;
1347 else if ((geo->fd = open(name,O_NOACCESS)) < 0)
1348 die("open %s: %s",name,strerror(errno));
1350 if (MAJOR(geo->dev) != MAJOR_FD) {
1351 if ((P_MASK(geo->dev) & geo->dev) != 0)
1352 die("UNSAFE may be used with floppy or MBR only");
1356 geo_get(geo, geo->dev, -1, 0);
1357 geo->file = S_ISREG(st.st_mode);
1365 void geo_close(GEOMETRY *geo)
1367 if (geo->fd) (void) close(geo->fd);
1373 #define FIBMAP BMAP_IOCTL
1377 int geo_comp_addr(GEOMETRY *geo,int offset,SECTOR_ADDR *addr)
1380 static int linear_warnings = 0;
1384 printf("geo_comp_addr: dev = %x, offset=%d\n",
1385 geo->device, offset);
1389 if (linear && lba32)
1390 die("'linear' and 'lba32' (-l and -L) are mutually exclusive.");
1392 if (geo->boot && offset >= SECTOR_SIZE)
1393 die("Internal error: sector > 0 after geo_open_boot");
1394 block = offset/geo->spb/SECTOR_SIZE;
1399 fstatfs(geo->fd, &buf);
1400 if (buf.f_type == REISERFS_SUPER_MAGIC) {
1401 if (ioctl (geo->fd, REISERFS_IOC_UNPACK, 1) == ENOSPC)
1402 die("Cannot unpack ReiserFS file");
1403 if (verbose > 3) printf("fd %d: REISERFS_IOC_UNPACK\n", geo->fd);
1405 /* Forcing reiser4 to perform tail2extent converstion */
1406 if (buf.f_type == REISER4_SUPER_MAGIC) {
1407 if (ioctl (geo->fd, REISER4_IOC_UNPACK, 1) != 0)
1408 die("Cannot unpack Reiser4 file");
1409 if (verbose > 3) printf("fd %d: REISER4_IOC_UNPACK\n", geo->fd);
1412 As we may have the situation when extent will be included
1413 into transaction, and its item(s) will not be have the real block
1414 numbers assigned, we should perform fsync() in order to guarantee,
1415 that current atom is flushed and real block numbers assigned to
1416 the extent(s) file was converted in.
1418 if (fdatasync(geo->fd) != 0)
1419 die("Cannot perform fdatasync");
1421 if (verbose > 3) printf("fd %d: fdatasync()\n", geo->fd);
1424 if (ioctl(geo->fd,FIBMAP,&block) < 0) pdie("ioctl FIBMAP");
1430 if (MAJOR(geo->dev) == MAJOR_LVM) {
1433 lbm.lv_dev = geo->dev;
1434 lbm.lv_block = block;
1437 if (lbm.lv_dev != geo->base_dev)
1438 die("LVM boot LV cannot be on multiple PVs\n");
1439 block = lbm.lv_block;
1444 if (MAJOR(geo->dev) == MAJOR_EVMS) {
1445 struct evms_get_bmap_t ebm;
1447 ebm.rsector = block * geo->spb;
1452 if (ebm.dev != geo->base_dev)
1453 die("EVMS boot volume cannot be on multiple disks.\n");
1454 sector = ebm.rsector + ((offset/SECTOR_SIZE) % geo->spb) + geo->start;
1459 #ifdef LCF_DEVMAPPER
1463 sector = block*geo->spb+((offset/SECTOR_SIZE) % geo->spb);
1464 #ifdef LCF_DEVMAPPER
1465 for(i = 0; i < dm_major_nr; i++)
1466 if (MAJOR(dev) == dm_major_list[i])
1468 while (i < dm_major_nr) {
1470 DM_TARGET *dm_target;
1472 for(dm_table = dmtab; dm_table; dm_table = dm_table->next)
1473 if (dm_table->device == dev)
1476 die("device-mapper: Mapped device suddenly lost? (%d)", dev);
1478 for(dm_target = dm_table->target; dm_target; dm_target = dm_target->next)
1479 if (dm_target->start <= sector && sector < (dm_target->start+dm_target->length))
1482 die("device-mapper: Sector outside mapped device? (%d: %u/%"PRIu64")",
1483 geo->base_dev, sector, (uint64_t)(dm_table->target ?
1484 (dm_table->target->start+dm_table->target->length) : 0));
1486 dev = dm_target->device;
1487 sector = dm_target->offset+(sector-dm_target->start);
1489 for(i = 0; i < dm_major_nr; i++)
1490 if (MAJOR(dev) == dm_major_list[i])
1494 if (dev != geo->dev && dev != geo->base_dev)
1495 die("device-mapper: mapped boot device cannot be on multiple real devices\n");
1497 sector += geo->start;
1500 /* DON'T always use CHS addressing on floppies: JRC */
1501 /* if ((geo->device & 0x80) && (linear || lba32)) { */
1502 if ((linear || lba32)) {
1503 addr->device = geo->device | (linear ? LINEAR_FLAG : (LBA32_FLAG|LBA32_NOCOUNT))
1505 | (do_md_install && geo->file==boot_dev_nr ? RAID_REL_FLAG : 0);
1507 | (do_md_install && geo->raid ? RAID_REL_FLAG : 0);
1509 addr->num_sect = linear ? 1 : (sector >> 24);
1510 addr->sector = sector & 0xff;
1511 addr->track = (sector >> 8) & 0xff;
1512 addr->head = sector >> 16;
1515 if (geo->sectors>0 && geo->heads>0) {
1516 cyl /= geo->sectors;
1518 if (cyl >= BIOS_MAX_CYLS && linear_warnings++ < 8) {
1519 warn("LINEAR may generate cylinder# above 1023 at boot-time.");
1522 if (sector/(63*255) >= BIOS_MAX_CYLS)
1523 die("Sector address %d too large for LINEAR"
1524 " (try LBA32 instead).", sector);
1527 printf("fd %d: offset %d -> dev 0x%02x, %s %d\n",
1528 geo->fd, offset, addr->device,
1529 lba32 ? "LBA" : "linear",
1533 addr->device = geo->device;
1537 if (geo->heads == 0)
1538 die("BIOS device 0x%02x is inaccessible", geo->device);
1539 addr->sector = (sector % geo->sectors)+1;
1540 sector /= geo->sectors;
1541 addr->head = sector % geo->heads;
1542 sector /= geo->heads;
1544 if (sector >= BIOS_MAX_CYLS)
1545 die("geo_comp_addr: Cylinder number is too big (%d > %d)",sector,
1547 if (sector >= geo->cylinders && geo->cylinders != -1)
1548 die("geo_comp_addr: Cylinder %d beyond end of media (%d)",sector,
1551 printf("fd %d: offset %d -> dev 0x%02x, head %d, track %d, sector %d\n",
1552 geo->fd,offset,addr->device,addr->head,sector,addr->sector);
1553 addr->track = sector & 255;
1554 addr->sector |= (sector >> 8) << 6;
1562 int geo_find(GEOMETRY *geo,SECTOR_ADDR addr)
1570 printf("Find: AL=%02x CX=%04x DX=%04x LBA=%d\n", (int)addr.num_sect,
1571 addr.sector + (addr.track<<8),
1572 addr.device + (addr.head<<8),
1573 addr.sector + (addr.track<<8) + (addr.head<<16) +
1574 (addr.device&(LBA32_FLAG|LBA32_NOCOUNT)?addr.num_sect<<24:0) );
1577 if (fstat(geo->fd,&st) < 0) return 0;
1578 geo_get(geo,st.st_dev,-1,1);
1579 for (i = 0; i < (st.st_size+SECTOR_SIZE-1)/SECTOR_SIZE; i++)
1580 if (geo_comp_addr(geo,i*SECTOR_SIZE,&here))
1581 if (here.sector == addr.sector && here.track == addr.track &&
1582 here.device == addr.device && here.head == addr.head &&
1583 here.num_sect == addr.num_sect ) {
1584 if (lseek(geo->fd,i*SECTOR_SIZE,SEEK_SET) < 0) return 0;
1592 int geo_devscan(int device)
1595 unsigned int mask, codes = 0;
1599 device &= D_MASK(device);
1601 /* mark those BIOS codes that are already used */
1602 for (walk=disktab; walk; walk=walk->next) {
1603 if (has_partitions(walk->device) && walk->bios != -1) {
1604 bios = walk->bios & 0x7F;
1605 if (bios >= 4*sizeof(codes) ) die("BIOS code %02X is too big (device %04X)", bios, device);
1611 /* extract BIOS code of master device, or -1 */
1612 for (walk=disktab; walk; walk=walk->next) {
1613 if (device == walk->device) {
1617 if (bios > maxbios) maxbios = bios;
1619 /* if device has no BIOS code assigned, assign the next one */
1621 for (bios=0x80, mask=1; mask; mask<<=1, bios++)
1622 if (!(mask&codes)) break;
1624 if (bios > DEV_MASK) die("geo_devscan: ran out of device codes");
1626 for (walk=disktab; walk; walk=walk->next) {
1627 if (device == walk->device) {
1628 if (walk->bios == -1) walk->bios = bios;
1629 else bios = walk->bios;
1633 if (bios > maxbios) maxbios = bios;
1635 if (verbose >= 2) printf("geo_devscan: maxbios = %02X\n", maxbios);
1637 if (walk) return maxbios; /* there was an entry in the disktab */
1639 walk = alloc_t(DT_ENTRY);
1640 walk->device = device;
1642 walk->sectors = walk->heads = walk->cylinders = walk->start = -1;
1643 walk->next = disktab;
1646 printf("geo_devscan: arbitrary bios assignment dev=%04X bios=0x%02X\n",
1649 for (walk=disktab; walk; walk=walk->next) {
1650 if (device == (walk->device & D_MASK(walk->device))) {
1651 if (walk->bios != -1) walk->bios = bios;