1 /* geometry.c - Device and file geometry computation
3 * Copyright 1992-1998 Werner Almesberger
4 * Copyright 1999-2005 John Coffman
5 * Copyright 2009-2014 Joachim Wiedorn
8 * Licensed under the terms contained in the file 'COPYING'
9 * in the source directory.
20 #include <sys/types.h>
23 #include <sys/statfs.h>
26 #define _I386_STATFS_H /* two versions of statfs is not good ... */
35 # include <libdevmapper.h>
47 #ifndef REISERFS_SUPER_MAGIC
48 #define REISERFS_SUPER_MAGIC 0x52654973
52 #ifndef REISERFS_SUPER_MAGIC_STRING
53 #define REISERFS_SUPER_MAGIC_STRING "ReIsErFs"
57 #ifndef REISERFS_IOC_UNPACK
58 #define REISERFS_IOC_UNPACK _IOW(0xCD,1,long)
61 #ifndef REISER4_SUPER_MAGIC
62 #define REISER4_SUPER_MAGIC 0x52345362
63 /* (*(__u32 *)"R4Sb"); */
65 #ifndef REISER4_IOC_UNPACK
66 #define REISER4_IOC_UNPACK _IOW(0xCD,1,long)
71 typedef struct _dm_target {
72 struct _dm_target *next;
73 uint64_t start,length,offset;
77 typedef struct _dm_table {
78 struct _dm_table *next;
80 struct _dm_target *target;
83 DM_TABLE *dmtab = NULL;
84 int dm_version_nr = 0;
87 int dm_major_list[16];
93 dev_t lv_dev; /* was __u16, which is wrong */
97 /* Should the definition be: */
98 #define LV_BMAP _IOWR(0xfe, 0x30, int)
99 /* As defined in the 2.4 kernels: */
100 /*#define LV_BMAP _IOWR(0xfe, 0x30, 1) */
102 #ifndef LVM_GET_IOP_VERSION
103 /* Should the definition be: */
104 #define LVM_GET_IOP_VERSION _IOR(0xfe, 0x98, unsigned short)
105 /* As defined in the 2.4 kernels: */
106 /*#define LVM_GET_IOP_VERSION _IOR(0xfe, 0x98, 1) */
111 struct evms_get_bmap_t {
117 struct evms_version_t {
123 #ifndef EVMS_GET_BMAP
124 #define EVMS_GET_BMAP _IOWR(MAJOR_EVMS, 0xC7, struct evms_get_bmap_t)
126 #ifndef EVMS_GET_IOCTL_VERSION
127 #define EVMS_GET_IOCTL_VERSION _IOR(MAJOR_EVMS, 0x0, struct evms_version_t)
132 #define HDIO_GETGEO HDIO_REQ
136 typedef struct _st_buf {
137 struct _st_buf *next;
142 DT_ENTRY *disktab = NULL;
146 void geo_init(char *name)
149 char line[MAX_LINE+1];
158 int disk_section,items;
161 if ((file = fopen(name,"r")) == NULL)
162 die("open %s: %s",name,strerror(errno));
164 if (name || (file = fopen(DFL_DISKTAB,"r")) != NULL) {
165 disk_section = !!disktab;
166 while (fgets(line,MAX_LINE,file)) {
167 here = strchr(line,'\n');
169 here = strchr(line,'#');
171 if (strspn(line," \t") != strlen(line)) {
172 entry = alloc_t(DT_ENTRY);
173 items = sscanf(line,"0x%x 0x%x %d %d %d %d",&entry->device,
174 (unsigned int*)&entry->bios,&entry->sectors,&entry->heads,&entry->cylinders,
176 if (items == 5) entry->start = -1;
178 die("Invalid line in %s:\n\"%s\"",name ? name : DFL_DISKTAB,
180 entry->next = disktab;
182 if (disk_section) die("DISKTAB and DISK are mutually exclusive");
190 file = fopen("/proc/devices", "r");
194 if (!fgets(line, (sizeof line)-1, file)) {
198 line[(sizeof line)-1] = 0;
199 } while(strncmp(line, "Block", 5) != 0);
201 while(fgets(line, (sizeof line)-1, file)) {
202 if (sscanf(line, "%d %31s\n", &major, major_name) != 2) continue;
203 if (strcmp(major_name, "device-mapper") != 0) continue;
204 dm_major_list[dm_major_nr] = major;
206 printf("device-mapper major = %d\n", major);
208 if (++dm_major_nr > nelem(dm_major_list) ) break;
215 /* Suppress error message if the device doesn't exist. It is ugly */
218 if (stat ("/dev/mapper/control", &fs))
221 if (!(dmt = dm_task_create(DM_DEVICE_VERSION)))
223 if (!dm_task_run(dmt))
225 if (!dm_task_get_driver_version(dmt, dm_version, sizeof dm_version))
229 * to not confuse returned device number formats %02x:%02x and %d:%d
230 * we assume here that the %02x:%02x format is only found in the ioctl
231 * interface version < 4 (this is really getting ugly...)
233 dm_version_nr = atoi(dm_version);
235 dm_task_destroy(dmt);
240 int is_dm_major(int major)
244 for(i=0; i<dm_major_nr; i++) {
245 if (dm_major_list[i] == major) return 1;
252 void do_partition(void)
254 DT_ENTRY *entry,*walk;
256 char *partition,*start;
258 entry = alloc_t(DT_ENTRY);
261 partition = cfg_get_strg(cf_partitions,"partition");
262 if (stat(partition,&st) < 0) die("stat %s: %s",partition,strerror(errno));
263 if (!S_ISBLK(st.st_mode) || ((st.st_rdev ^ disktab->device) & D_MASK(st.st_rdev)))
264 die("%s is not a valid partition device",partition);
265 entry->device = st.st_rdev;
266 cfg_init(cf_partition);
267 (void) cfg_parse(cf_partition);
268 start = cfg_get_strg(cf_partition,"start");
269 entry->start = start ? to_number(start) : -1;
270 for (walk = disktab; walk; walk = walk->next)
271 if (entry->device == walk->device)
272 die("Duplicate geometry definition for %s",partition);
273 entry->next = disktab;
275 cfg_init(cf_partitions);
279 int has_partitions_beta(dev_t dev)
281 int major = MAJOR(dev);
284 major == MAJOR_IDE ||
285 major == MAJOR_IDE2 ||
286 major == MAJOR_IDE3 ||
287 major == MAJOR_IDE4 ||
288 major == MAJOR_IDE5 ||
289 major == MAJOR_IDE6 ||
290 major == MAJOR_EMD ||
291 (major >= MAJOR_IDE7 && major <= MAJOR_IDE10) ||
293 major == MAJOR_ESDI ||
295 ) return 0xFFFFFFC0; /* 6 bit partition mask */
298 major == MAJOR_CARM1 ||
300 ) return 0xFFFFFFE0; /* 5 bit partition mask */
304 (major >= MAJOR_SD2 && major <= MAJOR_SD8) ||
305 (major >= MAJOR_SD9 && major <= MAJOR_SD16) ||
306 major == MAJOR_AMI ||
307 major == MAJOR_HPT370 ||
308 (major >= MAJOR_EXPR && major <= MAJOR_EXPR4) ||
309 (major >= MAJOR_EXPR5 && major <= MAJOR_EXPR12) ||
310 (major >= MAJOR_I2O && major <= MAJOR_I2O7) ||
311 (major >= MAJOR_SMART && major <= MAJOR_SMART8) ||
312 (major >= MAJOR_CISS && major <= MAJOR_CISS8) ||
313 major == MAJOR_FTL ||
314 major == MAJOR_NFTL ||
315 major == MAJOR_DOC ||
317 major == MAJOR_PPCD ||
318 major == MAJOR_PPFD ||
319 (major >= MAJOR_SATA1 && major <= MAJOR_SATA2)
320 ) return 0xFFFFFFF0; /* 4 bit partition mask */
323 major == MAJOR_IBM_ISER ||
324 (major >= MAJOR_DAC && major <= MAJOR_DAC8) ||
325 (major >= MAJOR_DAC9 && major <= MAJOR_DAC16)
326 ) return 0xFFFFFFF8; /* 3 bit partition mask */
333 unsigned char max_partno[512] = {
335 0 1 2 3 4 5 6 7 8 9 A B C D E F
337 0, 0, 0, 63, 0, 0, 0, 0, 15, 0, 0, 0, 0, 63, 0, 0, /* 0x */
338 0, 0, 0, 0, 0, 63, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0,
339 0, 63, 63, 0, 63, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0,
341 7, 7, 7, 7, 7, 7, 7, 7, 0, 63, 0, 0, 15, 15, 15, 15,
343 7, 7, 7, 7, 7, 7, 7, 7, 63, 63, 0, 0, 15, 15, 15, 15,
346 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, /* 4x */
347 15, 15, 15, 15, 15, 15, 15, 15, 63, 63, 63, 63, 0, 15, 0, 0,
348 0, 0, 0, 0, 15, 15, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15,
349 7, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
351 0 1 2 3 4 5 6 7 8 9 A B C D E F
353 15, 15, 15, 15, 15, 15, 15, 15, 7, 7, 7, 7, 7, 7, 7, 7, /* 8x */
354 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0,
355 31, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
356 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
358 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Cx */
359 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
360 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
361 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
363 0 1 2 3 4 5 6 7 8 9 A B C D E F
367 int has_partitions(dev_t dev)
369 int major = MAJOR(dev);
372 if (major >= nelem(max_partno)) {
373 warn("Major Device (%d) > %d",
374 major, nelem(max_partno)-1);
376 else if ( (ret=max_partno[major]) ) ret ^= 0xFFFFFFFF;
384 DT_ENTRY *entry,*walk;
386 char *disk,*bios,*sectors,*heads,*cylinders,*maxpart;
389 disk = cfg_get_strg(cf_options,"disk");
391 (void) cfg_parse(cf_disk);
392 if (stat(disk,&st) < 0) {
393 if (cfg_get_flag(cf_disk,"inaccessible")) {
394 cfg_unset(cf_options,"disk");
397 die("do_disk: stat %s: %s",disk,strerror(errno));
399 if (!S_ISBLK(st.st_mode) ||
400 (has_partitions(st.st_rdev) && (MINOR(st.st_rdev) & P_MASK(st.st_rdev))))
401 die(" '%s' is not a whole disk device",disk);
403 entry = alloc_t(DT_ENTRY);
404 entry->device = st.st_rdev;
405 major = MAJOR(st.st_rdev);
406 bios = cfg_get_strg(cf_disk,"bios");
407 sectors = cfg_get_strg(cf_disk,"sectors");
408 heads = cfg_get_strg(cf_disk,"heads");
409 cylinders = cfg_get_strg(cf_disk,"cylinders");
410 maxpart = cfg_get_strg(cf_disk,"max-partitions");
412 if (major<nelem(max_partno)) {
413 int i = to_number(maxpart);
414 if (max_partno[major] && max_partno[major]!=i) die("Cannot alter 'max-partitions' for known disk %s", disk);
415 max_partno[major] = i;
416 if (i!=7 && i!=15 && i!=31 && i!=63 && i!=128) die("disk=%s: illegal value for max-partitions(%d)", disk, i);
419 die("Implementation restriction: max-partitions on major device > %d", (int)nelem(max_partno)-1);
422 entry->bios = bios ? to_number(bios) : -1;
423 if (!sectors && !heads) entry->sectors = entry->heads = -1;
424 else if (!(sectors && heads))
425 die("Must specify SECTORS and HEADS together");
427 entry->sectors = to_number(sectors);
428 entry->heads = to_number(heads);
430 if (cfg_get_flag(cf_disk,"inaccessible")) {
432 if (bios) die("INACCESSIBLE and BIOS are mutually exclusive");
433 if ( sectors || heads || cylinders )
434 die("No geometry variables allowed if INACCESSIBLE");
436 entry->cylinders = cylinders ? to_number(cylinders) : -1;
438 for (walk = disktab; walk; walk = walk->next) {
439 if (entry->device == walk->device)
440 die("Duplicate \"disk =\" definition for %s",disk);
442 entry->next = disktab;
445 printf("do_disk: %s %04X 0x%02X %d:%d:%d\n",
446 disk, entry->device, entry->bios, entry->cylinders,
447 entry->heads, entry->sectors);
449 cfg_init(cf_partitions);
450 (void) cfg_parse(cf_partitions);
451 cfg_unset(cf_options,"disk");
455 static int exists(const char *name)
457 struct hd_geometry dummy;
461 if ((fd = open(name,O_RDWR)) < 0) return 0; /* was O_RDONLY */
462 yes = read(fd,&buff,1) == 1 && ioctl(fd,HDIO_GETGEO,&dummy) >= 0;
470 static int scan_last_dev(ST_BUF *next,char *parent,int major,int increment)
474 char name[PATH_MAX+1];
480 if ((dp = opendir(parent)) == NULL)
481 die("opendir %s: %s",parent,strerror(errno));
482 while ((dir = readdir(dp))) {
483 sprintf(name,"%s/%s",parent,dir->d_name);
484 if (stat(name,&st.st) >= 0) {
485 if (S_ISBLK(st.st.st_mode) && MAJOR(st.st.st_rdev) == major &&
486 (MINOR(st.st.st_rdev) & (increment-1)) == 0) {
487 this = MINOR(st.st.st_rdev)/increment+1;
488 if (this > max && exists(name)) max = this;
490 if (S_ISDIR(st.st.st_mode) && strcmp(dir->d_name,".") &&
491 strcmp(dir->d_name,"..")) {
492 for (walk = next; walk; walk = walk->next)
493 if (stat_equal(&walk->st,&st.st)) break;
495 this = scan_last_dev(&st,name,major,increment);
496 if (this > max) max = this;
508 static int last_dev(int major,int increment)
511 * Since last_dev is only used to count IDE drives anyway, we try
512 * now only the first two devices and forget about scan_last_dev.
516 static int cached_major=-1, cached_increment=-1, cached_result=-1;
517 if(major == cached_major && increment == cached_increment)
518 return cached_result;
519 cached_major = major;
520 cached_increment = increment;
524 devs < 2 && dev_open(&dev,MKDEV(major,increment*devs),O_BYPASS);
526 if (exists(dev.name)) dev_close(&dev);
531 cached_result = devs;
537 void lvm_bmap(struct lv_bmap *lbm)
540 static int lvmfd = -1;
541 static dev_t last_dev = 0;
543 if (lbm->lv_dev != last_dev) {
544 char lvm_char[] = DEV_DIR "/lvm";
550 if ((lvmfd = open(lvm_char, lbm->lv_dev, O_RDONLY)) < 0)
551 die("can't open LVM char device %s\n", lvm_char);
553 if (ioctl(lvmfd, LVM_GET_IOP_VERSION, &iop) < 0)
554 die("LVM_GET_IOP_VERSION failed on %s\n", lvm_char);
557 die("LVM IOP %d not supported for booting\n", iop);
560 lvmfd = dev_open(&dev, lbm->lv_dev, O_RDONLY);
562 die("can't open LVM block device %#x\n", (int)lbm->lv_dev);
563 last_dev = lbm->lv_dev;
565 if (ioctl(lvmfd, LV_BMAP, lbm) < 0) {
566 perror(__FUNCTION__);
567 pdie("LV_BMAP error or ioctl unsupported, can't have image in LVM.\n");
574 void evms_bmap(struct evms_get_bmap_t *ebm)
577 static int evms_fd = -1;
578 static dev_t evms_last_dev = 0;
580 if (ebm->dev != evms_last_dev) {
581 char evms_blk[] = DEV_DIR "/evms/block_device";
582 struct evms_version_t evms_ver;
584 /* Open the EVMS device */
588 evms_fd = open(evms_blk, O_RDONLY);
590 die("Can't open EVMS block device %s.\n", evms_blk);
592 /* Get EVMS ioctl version number. */
593 if (ioctl(evms_fd, EVMS_GET_IOCTL_VERSION, &evms_ver) < 0)
594 die("EVMS_GET_IOCTL_VERSION failed on %s.\n", evms_blk);
596 /* Check that the ioctl version is >= 7.1.0 */
597 if (evms_ver.major < 7 ||
598 (evms_ver.major == 7 && evms_ver.minor < 1))
599 die("EVMS ioctl version %d.%d.%d does not support booting.\n",
600 evms_ver.major, evms_ver.minor, evms_ver.patch);
603 evms_fd = dev_open(&dev, ebm->dev, O_RDONLY);
605 die("Can't open EVMS block device %#x\n", ebm->dev);
606 evms_last_dev = ebm->dev;
609 if (ioctl(evms_fd, EVMS_GET_BMAP, ebm) < 0) {
610 perror(__FUNCTION__);
611 pdie("EVMS_GET_BMAP error or ioctl unsupported. Can't have image on EVMS volume.\n");
617 void geo_query_dev(GEOMETRY *geo,int device,int all)
620 int fd,get_all,major;
621 struct floppy_struct fdprm;
622 struct hd_geometry hdprm;
624 if (verbose>=5) printf("geo_query_dev: device=%04X\n", device);
625 /* simplified condition -- JRC 2003-06-04 */
629 die("Trying to map files from unnamed device 0x%04x (NFS/RAID mirror down ?)",device);
630 if (device == MAJMIN_RAM)
631 die("Trying to map files from your RAM disk. "
632 "Please check -r option or ROOT environment variable.");
634 fd = dev_open(&dev,device,O_NOACCESS);
637 fd = -1; /* pacify GCC */
638 geo->heads = geo->cylinders = geo->sectors = 1;
642 switch ((major=MAJOR(device))) {
644 geo->device = device & 3;
646 if (ioctl(fd,FDGETPRM,&fdprm) < 0)
647 die("geo_query_dev FDGETPRM (dev 0x%04x): %s",device,
649 geo->heads = fdprm.head;
650 geo->cylinders = fdprm.track;
651 geo->sectors = fdprm.sect;
668 geo->device = 0x80 + (MINOR(device) >> 6) +
669 (MAJOR(device) == MAJOR_IDE ? 0 : last_dev(MAJOR_IDE,64));
671 if (ioctl(fd,HDIO_GETGEO,&hdprm) < 0)
672 die("geo_query_dev HDIO_GETGEO (dev 0x%04x): %s",device,
674 geo->heads = hdprm.heads;
675 geo->cylinders = hdprm.cylinders;
676 geo->sectors = hdprm.sectors;
677 geo->start = hdprm.start;
697 geo->device = 0x80 + last_dev(MAJOR_IDE,64) + (MINOR(device) >> 4);
699 if (ioctl(fd,HDIO_GETGEO,&hdprm) < 0)
700 die("geo_query_dev HDIO_GETGEO (dev 0x%04x): %s",device,
702 if (all && !hdprm.sectors)
703 die("HDIO_REQ not supported for your SCSI controller. Please "
704 "use a DISK section");
705 geo->heads = hdprm.heads;
706 geo->cylinders = hdprm.cylinders;
707 geo->sectors = hdprm.sectors;
708 geo->start = hdprm.start;
712 printf("WARNING: SATA partition in the high region (>15):\n");
713 printf("LILO needs the kernel in one of the first 15 SATA partitions. If \n");
714 printf("you need support for kernel in SATA partitions of the high region \n");
715 printf("than try grub2 for this purpose! \n");
716 die("Sorry, cannot handle device 0x%04x",device);
719 geo->device = 0x80 + last_dev(MAJOR_IDE,64) + (MINOR(device) >> 5);
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 Disk controller. Please "
726 "use a DISK section");
727 geo->heads = hdprm.heads;
728 geo->cylinders = hdprm.cylinders;
729 geo->sectors = hdprm.sectors;
730 geo->start = hdprm.start;
751 geo->device = 0x80 + last_dev(MAJOR_IDE,64) + (MINOR(device) >> 3);
753 if (ioctl(fd,HDIO_GETGEO,&hdprm) < 0)
754 die("geo_query_dev HDIO_GETGEO (dev 0x%04x): %s",device,
756 if (all && !hdprm.sectors)
757 die("HDIO_REQ not supported for your DAC960/IBM controller. "
758 "Please use a DISK section");
759 geo->heads = hdprm.heads;
760 geo->cylinders = hdprm.cylinders;
761 geo->sectors = hdprm.sectors;
762 geo->start = hdprm.start;
808 geo->device = 0x80 + last_dev(MAJOR_IDE,64) + (MINOR(device) >> 4);
810 if (ioctl(fd,HDIO_GETGEO,&hdprm) < 0)
811 die("geo_query_dev HDIO_GETGEO (dev 0x%04x): %s",device,
813 if (all && !hdprm.sectors)
814 die("HDIO_REQ not supported for your Array controller. Please "
815 "use a DISK section");
816 geo->heads = hdprm.heads;
817 geo->cylinders = hdprm.cylinders;
818 geo->sectors = hdprm.sectors;
819 geo->start = hdprm.start;
823 if (max_partno[major] && major==MAJOR_LOOP) break;
824 if (max_partno[major] == 63) goto MASK63;
825 if (max_partno[major] == 31) goto MASK31;
826 if (max_partno[major] == 15) goto MASK15;
827 if (max_partno[major] == 7) goto MASK7;
829 if ((MAJOR(device)>=60 && MAJOR(device)<=63) ||
830 (MAJOR(device)>=120 && MAJOR(device)<=127) ||
831 (MAJOR(device)>=240 && MAJOR(device)<=254) )
832 die("Linux experimental device 0x%04x needs to be defined.\n"
833 "Check 'man lilo.conf' under 'disk=' and 'max-partitions='", device);
834 else die("Sorry, don't know how to handle device 0x%04x",device);
836 if (get_all) dev_close(&dev);
837 if (verbose>=5) printf("exit geo_query_dev\n");
841 int is_first(int device)
845 for (walk = disktab; walk; walk = walk->next)
846 if (walk->device == device) break;
847 if (!walk && !old_disktab)
848 for (walk = disktab; walk; walk = walk->next)
849 if (walk->device == (device & D_MASK(device))) break;
850 if (walk && !walk->heads)
851 die("Device 0x%04X: Configured as inaccessible.\n",device);
852 if (walk && walk->bios != -1) return !(walk->bios & 0x7f);
854 switch (MAJOR(device)) {
856 return !(device & 3);
859 return !(MINOR(device) >> 6);
872 return MINOR(device) >> 6 ? 0 : !last_dev(MAJOR_IDE,64);
934 return MINOR(device) >> 4 ? 0 : !last_dev(MAJOR_IDE,64);
954 return MINOR(device) >> 3 ? 0 : !last_dev(MAJOR_IDE,64);
957 return 1; /* user knows what (s)he's doing ... I hope */
962 void geo_get(GEOMETRY *geo,int device,int user_device,int all)
965 int inherited,keep_cyls,is_raid=0;
969 for(i = 0; i < dm_major_nr; i++)
970 if (MAJOR(device) == dm_major_list[i])
972 while (i < dm_major_nr) {
975 for(dm_table = dmtab; dm_table; dm_table = dm_table->next)
976 if (dm_table->device == device)
983 for(target = dm_table->target; target; target = target->next)
984 device = target->device;
989 char dmdev[PATH_MAX+1];
990 char buf[PATH_MAX+1];
994 dev_open(&dev, device, -1);
995 strncpy(dmdev, dev.name, PATH_MAX);
998 memset(buf, 0, PATH_MAX + 1);
999 if ((result = readlink(dmdev, buf, PATH_MAX)) < 0 && errno != EINVAL)
1000 die("device-mapper: readlink(\"%s\") failed with: %s",buf,
1003 if (buf[0] != '/' && (slash = strrchr(dmdev, '/')) != NULL)
1007 strncpy(slash, buf, PATH_MAX - (slash-dmdev));
1009 if (realpath(dmdev, buf) == NULL)
1010 die("device-mapper: realpath(\"%s\") failed with: %s",dmdev,
1012 strncpy(dmdev, buf, PATH_MAX);
1013 } while (result >= 0);
1014 dmdev[PATH_MAX] = 0;
1016 if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
1017 die("device-mapper: dm_task_create(DM_DEVICE_TABLE) failed");
1018 slash = strrchr(dmdev, '/');
1023 if (!dm_task_set_major(dmt, MAJOR(device)) ||
1024 !dm_task_set_minor(dmt, MINOR(device)))
1025 die("device-mapper: dm_task_set_major() or dm_task_set_minor() failed");
1026 if (!dm_task_run(dmt))
1027 die("device-mapper: dm_task_run(DM_DEVICE_TABLE) failed");
1029 dm_table = alloc_t(DM_TABLE);
1030 dm_table->device = device;
1031 dm_table->target = NULL;
1032 dm_table->next = dmtab;
1039 uint64_t start,length;
1041 char *target_type,*params;
1044 next = dm_get_next_target(dmt, next, &start, &length,
1045 &target_type, ¶ms);
1047 if (!target_type) continue;
1049 if (strcmp(target_type, "linear") != 0)
1050 die("device-mapper: only linear boot device supported");
1052 target = alloc_t(DM_TARGET);
1053 target->start = start;
1054 target->length = length;
1055 if (dm_version_nr < 4 &&
1056 isxdigit(params[0]) &&
1057 isxdigit(params[1]) &&
1059 isxdigit(params[3]) &&
1060 isxdigit(params[4])) { /* old 2.4 format */
1061 if (sscanf(params, "%02x:%02x %"PRIu64, &major, &minor, &target->offset) != 3)
1062 die("device-mapper: parse error in linear params (\"%s\")", params);
1063 } else if (isdigit(params[0]) &&
1064 strchr(params, ':')) { /* dm_bdevname/format_dev_t (>= 2.6.0-test4?) format */
1065 if (sscanf(params, "%u:%u %"PRIu64, &major, &minor, &target->offset) != 3)
1066 die("device-mapper: parse error in linear params (\"%s\")", params);
1067 } else { /* >= 2.5.69 format, this should go away soon */
1071 p = strrchr(params, ' ');
1073 die("device-mapper: parse error in linear params (\"%s\")", params);
1075 sprintf(buf, DEV_DIR "/%s", params); /* let's hope it's there */
1076 if (stat(buf, &st) == 0) {
1077 if (!S_ISBLK(st.st_mode))
1078 die("device-mapper: %s is not a valid block device", buf);
1079 major = MAJOR(st.st_rdev);
1080 minor = MINOR(st.st_rdev);
1081 } else { /* let's try sysfs */
1083 sprintf(buf, "/sys/block/%s/dev", params);
1084 file = fopen(buf, "r");
1086 die("device-mapper: \"%s\" could not be opened. /sys mounted?", buf);
1087 if (!fgets(buf, PATH_MAX, file))
1088 die("device-mapper: read error from \"/sys/block/%s/dev\"", params);
1089 if (sscanf(buf, "%u:%u", &major, &minor) != 2) {
1090 if (sscanf(buf, "%x", &dev) != 1)
1091 die("device-mapper: error getting device from \"%s\"", buf);
1095 (void) fclose(file);
1098 if (sscanf(p+1, "%"PRIu64, &target->offset) != 1)
1099 die("device-mapper: parse error in linear params (\"%s\")", params);
1101 target->device = (major << 8) | minor;
1103 device = target->device;
1104 target->next = dm_table->target;
1105 dm_table->target = target;
1108 dm_task_destroy(dmt);
1114 die("device-mapper: Error finding real device");
1115 geo->base_dev = device;
1117 for(i = 0; i < dm_major_nr; i++)
1118 if (MAJOR(device) == dm_major_list[i])
1123 if (verbose>=5) printf("geo_get: device %04X, all=%d\n", device, all);
1126 * Find underlying device (PV) for LVM. It is OK if the underlying PV is
1127 * really an MD RAID1 device, because the geometry of the RAID1 device is
1128 * exactly the same as the underlying disk, so FIBMAP and LV_BMAP should
1129 * return the correct block numbers regardless of MD.
1131 * We do a quick test to see if the LVM LV_BMAP ioctl is working correctly.
1132 * It should map the two blocks with the same difference as they were input,
1133 * with a constant offset from their original block numbers. If this is not
1134 * the case then LV_BMAP is not working correctly (some widely distributed
1135 * kernels did not have working LV_BMAP support, some just oops here).
1137 if (MAJOR(device) == MAJOR_LVM)
1139 struct lv_bmap lbmA, lbmB;
1142 lbmA.lv_dev = lbmB.lv_dev = device;
1144 lbmB.lv_block = DIFF;
1148 if (lbmB.lv_block - lbmA.lv_block != DIFF)
1149 die("This version of LVM does not support boot LVs");
1150 device = geo->base_dev = lbmA.lv_dev;
1155 if (MAJOR(device) == MAJOR_EVMS) {
1156 struct evms_get_bmap_t ebm;
1164 device = geo->base_dev = ebm.dev;
1168 /* Find underlying device for MD RAID */
1169 if (MAJOR(device) == MD_MAJOR) {
1173 struct md_version md_version_info;
1174 md_array_info_t md_array_info;
1175 md_disk_info_t md_disk_info;
1179 sprintf(mdxxx, DEV_DISK_DIR "/md%d", MINOR(device));
1180 if ((md_fd=open(mdxxx,O_NOACCESS)) < 0)
1182 sprintf(mdxxx, DEV_DIR "/md/%d", MINOR(device));
1183 if ((md_fd=open(mdxxx,O_NOACCESS)) < 0)
1184 die("Unable to open %s", mdxxx);
1186 if (ioctl(md_fd,RAID_VERSION,&md_version_info) < 0)
1187 die("Unable to get RAID version on %s", mdxxx);
1188 if (md_version_info.major > 0)
1189 die("Raid major versions > 0 are not supported");
1190 if (md_version_info.minor < 90)
1191 die("Raid versions < 0.90 are not supported");
1193 if (ioctl(md_fd,GET_ARRAY_INFO,&md_array_info) < 0)
1194 die("Unable to get RAID info on %s", mdxxx);
1195 if (md_version_info.major != 0 || md_version_info.minor != 90 ||
1196 ((md_array_info.major_version != 0 ||
1197 md_array_info.minor_version != 90) &&
1198 (md_array_info.major_version != 1 ||
1199 md_array_info.minor_version != 0))
1201 die("Incompatible Raid version information on %s (RV=%d.%d GAI=%d.%d)",
1203 (int)md_version_info.major,
1204 (int)md_version_info.minor,
1205 (int)md_array_info.major_version,
1206 (int)md_array_info.minor_version);
1208 if (md_array_info.level != 1)
1209 die("Only RAID1 devices are supported for boot images");
1210 raid_limit = md_array_info.raid_disks + md_array_info.spare_disks;
1214 is_raid = (device==boot_dev_nr);
1215 md_disk_info.number = raid_index;
1216 if (ioctl(md_fd,GET_DISK_INFO,&md_disk_info) < 0)
1217 die("GET_DISK_INFO: %s", mdxxx);
1218 device = MKDEV(md_disk_info.major, md_disk_info.minor);
1220 #else /* prior to 22.7 */
1223 for (pass = 0; pass < raid_limit; pass++) {
1224 md_disk_info.number = pass;
1225 if (ioctl(md_fd,GET_DISK_INFO,&md_disk_info) < 0)
1228 printf("(raid) GET_DISK_INFO: failed for pass=%d\n", pass);
1232 die("GET_DISK_INFO: %s", mdxxx);
1234 if (!(md_disk_info.state & (1 << MD_DISK_FAULTY))) {
1236 is_raid = (device==boot_dev_nr);
1238 /* this change may be in error; the correct comparison is == */
1239 is_raid = (device!=boot_dev_nr);
1241 device = MKDEV(md_disk_info.major, md_disk_info.minor);
1246 #endif /* end of code prior to version 22.7 */
1252 if (verbose>=5) printf("geo_get(2): device=%04X, all=%d\n", device, all);
1255 /* if using hard disk, scan the devices in /proc/partitions */
1256 if (has_partitions(device) && all) pf_hard_disk_scan();
1261 for (walk = disktab; walk; walk = walk->next)
1262 if (walk->device == device) break;
1263 inherited = !walk && !old_disktab;
1265 if (verbose>=5) printf("inherited=%d\n", inherited);
1268 for (walk = disktab; walk; walk = walk->next)
1269 if (walk->device == (device & D_MASK(device))) break;
1271 if (verbose>=5) printf("walk=%08lx\n", (long)walk);
1275 /* add 'all' to conditional below -- JRC 2002-08-20 */
1276 if (walk && !walk->heads && all)
1278 /* Werner's original conditional */
1279 if (walk && !walk->heads)
1281 die("Device 0x%04X: Configured as inaccessible.\n",device);
1282 keep_cyls = !walk || walk->bios == -1 || walk->heads == -1 ||
1283 walk->sectors == -1 || inherited || walk->start == -1;
1285 if (verbose>=5) printf("inherited=%d keep_cyls=%d\n", inherited, keep_cyls);
1289 /* add 'all' to conditional below -- JRC 2002-08-20 */
1290 if (keep_cyls && (all || MAJOR(device)==MAJOR_FD) ) {
1292 /* Werner's original conditional */
1295 geo_query_dev(geo,device,all);
1297 if (all) bios_device(geo, device);
1299 if ((geo->device & 0x7f) >= bios_max_devs() &&
1300 user_device == -1 && (!walk || walk->bios == -1))
1301 warn("BIOS drive 0x%02x may not be accessible",
1305 if (walk->bios != -1) geo->device = walk->bios;
1306 if (walk->heads != -1) geo->heads = walk->heads;
1307 if (walk->cylinders != -1 || !keep_cyls)
1308 geo->cylinders = walk->cylinders;
1309 if (walk->sectors != -1) geo->sectors = walk->sectors;
1310 if (walk->start != -1 && !inherited) geo->start = walk->start;
1312 if (user_device != -1) geo->device = user_device;
1315 printf("Device 0x%04x: BIOS drive 0x%02x, no geometry.\n",device,
1319 if (!geo->heads || !geo->cylinders || !geo->sectors)
1320 die("Device 0x%04X: Got bad geometry %d/%d/%d\n",device,
1321 geo->sectors,geo->heads,geo->cylinders);
1322 if (geo->heads > BIOS_MAX_HEADS)
1323 die("Device 0x%04X: Maximum number of heads is %d, not %d\n",device,
1324 BIOS_MAX_HEADS,geo->heads);
1325 if (geo->heads == BIOS_MAX_HEADS)
1326 warn("Maximum number of heads = %d (as specified)\n"
1327 " exceeds standard BIOS maximum of 255.", geo->heads);
1328 if (geo->sectors > BIOS_MAX_SECS)
1329 die("Device 0x%04X: Maximum number of sectors is %d, not %d\n",
1330 device,BIOS_MAX_SECS,geo->sectors);
1331 if (geo->sectors == BIOS_MAX_SECS)
1332 warn("Maximum number of heads = %d (as specified)\n"
1333 " exceeds standard BIOS maximum of 63.", geo->sectors);
1335 (geo->start+geo->sectors-1)/geo->heads/geo->sectors >= BIOS_MAX_CYLS
1337 warn("device 0x%04x exceeds %d cylinder limit.\n"
1338 " Use of the 'lba32' option may help on newer (EDD-BIOS) systems.",
1339 device, BIOS_MAX_CYLS);
1342 printf("Device 0x%04x: BIOS drive 0x%02x, %d heads, %d cylinders,\n",
1343 device,geo->device,geo->heads,geo->cylinders == -1 ? BIOS_MAX_CYLS :
1345 printf("%15s%d sectors. Partition offset: %d sectors.\n","",
1346 geo->sectors,geo->start);
1348 geo->raid = is_raid;
1350 /* make the serial number association */
1351 if (!is_raid) register_bios(geo->device, device);
1352 else geo->device = md_bios; /* 22.5.7 add this else */
1355 } /* end of geo_get */
1358 int geo_open(GEOMETRY *geo,const char *name,int flags)
1361 int user_dev,block_size;
1364 if ((here = strrchr(name,':')) == NULL) user_dev = -1;
1367 warn("%s:BIOS syntax is no longer supported.\n Please use a "
1368 "DISK section.", name);
1369 user_dev = to_number(here);
1371 if ((geo->fd = open(name,flags)) < 0)
1372 die("open %s: %s",name,strerror(errno));
1373 if (fstat(geo->fd,&st) < 0) die("fstat %s: %s",name,strerror(errno));
1374 if (!S_ISREG(st.st_mode) && !S_ISBLK(st.st_mode))
1375 die("%s: neither a reg. file nor a block dev.",name);
1376 geo->dev = S_ISREG(st.st_mode) ? st.st_dev : st.st_rdev;
1379 printf("geo_open: (%s) st_dev(file)=%04X st_rdev(blk)=%04X\n",
1386 geo_get(geo, geo->dev, user_dev, 1);
1387 geo->file = S_ISREG(st.st_mode) ? st.st_dev : 0;
1392 if (!geo->file) geo->spb = 2;
1394 if (ioctl(geo->fd,FIGETBSZ,&block_size) < 0) {
1395 warn("FIGETBSZ %s: %s",name,strerror(errno));
1399 if (!block_size || (block_size & (SECTOR_SIZE-1)))
1400 die("Incompatible block size: %d\n",block_size);
1401 geo->spb = block_size/SECTOR_SIZE;
1409 int geo_open_boot(GEOMETRY *geo,char *name)
1413 if (verbose>=5) printf("geo_open_boot: %s\n", name);
1414 if (stat(name,&st) < 0) die("stat %s: %s",name,strerror(errno));
1415 if (!S_ISREG(st.st_mode) && !S_ISBLK(st.st_mode))
1416 die("%s: neither a reg. file nor a block dev.",name);
1417 geo->dev = S_ISREG(st.st_mode) ? st.st_dev : st.st_rdev;
1419 if (MAJOR(geo->dev) == MAJOR_FD) geo->fd = 0;
1420 else if ((geo->fd = open(name,O_NOACCESS)) < 0)
1421 die("open %s: %s",name,strerror(errno));
1423 if (MAJOR(geo->dev) != MAJOR_FD) {
1424 if ((P_MASK(geo->dev) & geo->dev) != 0)
1425 die("UNSAFE may be used with floppy or MBR only");
1429 geo_get(geo, geo->dev, -1, 0);
1430 geo->file = S_ISREG(st.st_mode);
1438 void geo_close(GEOMETRY *geo)
1440 if (geo->fd) (void) close(geo->fd);
1446 #define FIBMAP BMAP_IOCTL
1450 int geo_comp_addr(GEOMETRY *geo,int offset,SECTOR_ADDR *addr)
1453 static int linear_warnings = 0;
1457 printf("geo_comp_addr: dev = %x, offset=%d\n",
1458 geo->device, offset);
1462 if (linear && lba32)
1463 die("'linear' and 'lba32' (-l and -L) are mutually exclusive.");
1465 if (geo->boot && offset >= SECTOR_SIZE)
1466 die("Internal error: sector > 0 after geo_open_boot");
1467 block = offset/geo->spb/SECTOR_SIZE;
1472 fstatfs(geo->fd, &buf);
1473 if (buf.f_type == REISERFS_SUPER_MAGIC) {
1474 if (ioctl (geo->fd, REISERFS_IOC_UNPACK, 1) == ENOSPC)
1475 die("Cannot unpack ReiserFS file");
1476 if (verbose > 3) printf("fd %d: REISERFS_IOC_UNPACK\n", geo->fd);
1478 /* Forcing reiser4 to perform tail2extent converstion */
1479 if (buf.f_type == REISER4_SUPER_MAGIC) {
1480 if (ioctl (geo->fd, REISER4_IOC_UNPACK, 1) != 0)
1481 die("Cannot unpack Reiser4 file");
1482 if (verbose > 3) printf("fd %d: REISER4_IOC_UNPACK\n", geo->fd);
1485 As we may have the situation when extent will be included
1486 into transaction, and its item(s) will not be have the real block
1487 numbers assigned, we should perform fsync() in order to guarantee,
1488 that current atom is flushed and real block numbers assigned to
1489 the extent(s) file was converted in.
1491 if (fdatasync(geo->fd) != 0)
1492 die("Cannot perform fdatasync");
1494 if (verbose > 3) printf("fd %d: fdatasync()\n", geo->fd);
1497 if (ioctl(geo->fd,FIBMAP,&block) < 0) pdie("ioctl FIBMAP");
1503 if (MAJOR(geo->dev) == MAJOR_LVM) {
1506 lbm.lv_dev = geo->dev;
1507 lbm.lv_block = block;
1510 if (lbm.lv_dev != geo->base_dev)
1511 die("LVM boot LV cannot be on multiple PVs\n");
1512 block = lbm.lv_block;
1517 if (MAJOR(geo->dev) == MAJOR_EVMS) {
1518 struct evms_get_bmap_t ebm;
1520 ebm.rsector = block * geo->spb;
1525 if (ebm.dev != geo->base_dev)
1526 die("EVMS boot volume cannot be on multiple disks.\n");
1527 sector = ebm.rsector + ((offset/SECTOR_SIZE) % geo->spb) + geo->start;
1532 #ifdef LCF_DEVMAPPER
1536 sector = block*geo->spb+((offset/SECTOR_SIZE) % geo->spb);
1537 #ifdef LCF_DEVMAPPER
1538 for(i = 0; i < dm_major_nr; i++)
1539 if (MAJOR(dev) == dm_major_list[i])
1541 while (i < dm_major_nr) {
1543 DM_TARGET *dm_target;
1545 for(dm_table = dmtab; dm_table; dm_table = dm_table->next)
1546 if (dm_table->device == dev)
1549 die("device-mapper: Mapped device suddenly lost? (%d)", dev);
1551 for(dm_target = dm_table->target; dm_target; dm_target = dm_target->next)
1552 if (dm_target->start <= sector && sector < (dm_target->start+dm_target->length))
1555 die("device-mapper: Sector outside mapped device? (%d: %u/%"PRIu64")",
1556 (int) geo->base_dev, sector, (uint64_t)(dm_table->target ?
1557 (dm_table->target->start+dm_table->target->length) : 0));
1559 dev = dm_target->device;
1560 sector = dm_target->offset+(sector-dm_target->start);
1562 for(i = 0; i < dm_major_nr; i++)
1563 if (MAJOR(dev) == dm_major_list[i])
1567 if (dev != geo->dev && dev != geo->base_dev)
1568 die("device-mapper: mapped boot device cannot be on multiple real devices\n");
1570 sector += geo->start;
1573 /* DON'T always use CHS addressing on floppies: JRC */
1574 /* if ((geo->device & 0x80) && (linear || lba32)) { */
1575 if ((linear || lba32)) {
1576 addr->device = geo->device | (linear ? LINEAR_FLAG : (LBA32_FLAG|LBA32_NOCOUNT))
1578 | (do_md_install && geo->file==boot_dev_nr ? RAID_REL_FLAG : 0);
1580 | (do_md_install && geo->raid ? RAID_REL_FLAG : 0);
1582 addr->num_sect = linear ? 1 : (sector >> 24);
1583 addr->sector = sector & 0xff;
1584 addr->track = (sector >> 8) & 0xff;
1585 addr->head = sector >> 16;
1588 if (geo->sectors>0 && geo->heads>0) {
1589 cyl /= geo->sectors;
1591 if (cyl >= BIOS_MAX_CYLS && linear_warnings++ < 8) {
1592 warn("LINEAR may generate cylinder# above 1023 at boot-time.");
1595 if (sector/(63*255) >= BIOS_MAX_CYLS)
1596 die("Sector address %d too large for LINEAR"
1597 " (try LBA32 instead).", sector);
1600 printf("fd %d: offset %d -> dev 0x%02x, %s %d\n",
1601 geo->fd, offset, addr->device,
1602 lba32 ? "LBA" : "linear",
1606 addr->device = geo->device;
1610 if (geo->heads == 0)
1611 die("BIOS device 0x%02x is inaccessible", geo->device);
1612 addr->sector = (sector % geo->sectors)+1;
1613 sector /= geo->sectors;
1614 addr->head = sector % geo->heads;
1615 sector /= geo->heads;
1617 if (sector >= BIOS_MAX_CYLS)
1618 die("geo_comp_addr: Cylinder number is too big (%d > %d)",sector,
1620 if (sector >= geo->cylinders && geo->cylinders != -1)
1621 die("geo_comp_addr: Cylinder %d beyond end of media (%d)",sector,
1624 printf("fd %d: offset %d -> dev 0x%02x, head %d, track %d, sector %d\n",
1625 geo->fd,offset,addr->device,addr->head,sector,addr->sector);
1626 addr->track = sector & 255;
1627 addr->sector |= (sector >> 8) << 6;
1635 int geo_find(GEOMETRY *geo,SECTOR_ADDR addr)
1643 printf("Find: AL=%02x CX=%04x DX=%04x LBA=%d\n", (int)addr.num_sect,
1644 addr.sector + (addr.track<<8),
1645 addr.device + (addr.head<<8),
1646 addr.sector + (addr.track<<8) + (addr.head<<16) +
1647 (addr.device&(LBA32_FLAG|LBA32_NOCOUNT)?addr.num_sect<<24:0) );
1650 if (fstat(geo->fd,&st) < 0) return 0;
1651 geo_get(geo,st.st_dev,-1,1);
1652 for (i = 0; i < (st.st_size+SECTOR_SIZE-1)/SECTOR_SIZE; i++)
1653 if (geo_comp_addr(geo,i*SECTOR_SIZE,&here))
1654 if (here.sector == addr.sector && here.track == addr.track &&
1655 here.device == addr.device && here.head == addr.head &&
1656 here.num_sect == addr.num_sect ) {
1657 if (lseek(geo->fd,i*SECTOR_SIZE,SEEK_SET) < 0) return 0;
1665 int geo_devscan(int device)
1668 unsigned int mask, codes = 0;
1672 device &= D_MASK(device);
1674 /* mark those BIOS codes that are already used */
1675 for (walk=disktab; walk; walk=walk->next) {
1676 if (has_partitions(walk->device) && walk->bios != -1) {
1677 bios = walk->bios & 0x7F;
1678 if (bios >= 4*sizeof(codes) ) die("BIOS code %02X is too big (device %04X)", bios, device);
1684 /* extract BIOS code of master device, or -1 */
1685 for (walk=disktab; walk; walk=walk->next) {
1686 if (device == walk->device) {
1690 if (bios > maxbios) maxbios = bios;
1692 /* if device has no BIOS code assigned, assign the next one */
1694 for (bios=0x80, mask=1; mask; mask<<=1, bios++)
1695 if (!(mask&codes)) break;
1697 if (bios > DEV_MASK) die("geo_devscan: ran out of device codes");
1699 for (walk=disktab; walk; walk=walk->next) {
1700 if (device == walk->device) {
1701 if (walk->bios == -1) walk->bios = bios;
1702 else bios = walk->bios;
1706 if (bios > maxbios) maxbios = bios;
1708 if (verbose >= 2) printf("geo_devscan: maxbios = %02X\n", maxbios);
1710 if (walk) return maxbios; /* there was an entry in the disktab */
1712 walk = alloc_t(DT_ENTRY);
1713 walk->device = device;
1715 walk->sectors = walk->heads = walk->cylinders = walk->start = -1;
1716 walk->next = disktab;
1719 printf("geo_devscan: arbitrary bios assignment dev=%04X bios=0x%02X\n",
1722 for (walk=disktab; walk; walk=walk->next) {
1723 if (device == (walk->device & D_MASK(walk->device))) {
1724 if (walk->bios != -1) walk->bios = bios;