Imported Upstream version 23.2
[rrq/maintain_lilo.git] / src / geometry.c
1 /* geometry.c  -  Device and file geometry computation */
2 /*
3 Copyright 1992-1998 Werner Almesberger.
4 Copyright 1999-2005 John Coffman.
5 All rights reserved.
6
7 Licensed under the terms contained in the file 'COPYING' in the 
8 source directory.
9
10 */
11 /* Patched for linux-2.4.0 - Glibc-2.2 by Sergey Ostrovsky 11/16/2000 */
12
13 #define _GNU_SOURCE
14 #include <unistd.h>
15 #include <stdio.h>
16 #include <fcntl.h>
17 #include <errno.h>
18 #include <stdlib.h>
19 #include <limits.h>
20 #include <ctype.h>
21 #include <sys/types.h>
22
23 #ifdef LCF_REISERFS
24 #include <sys/statfs.h>
25
26 #ifdef  _SYS_STATFS_H
27 #define _I386_STATFS_H  /* two versions of statfs is not good ... */
28 #endif
29 #endif
30
31 #include <string.h>
32
33
34 #include "config.h"
35 #ifdef LCF_DEVMAPPER
36 # include <libdevmapper.h>
37 #endif
38 #include "lilo.h"
39 #include "common.h"
40 #include "device.h"
41 #include "raid.h"
42 #include "geometry.h"
43 #include "cfg.h"
44 #include "md-int.h"
45 #include "probe.h"
46
47 #ifdef LCF_REISERFS
48 #ifndef REISERFS_SUPER_MAGIC
49 #define REISERFS_SUPER_MAGIC 0x52654973
50 #endif
51
52 #if 0
53 #ifndef REISERFS_SUPER_MAGIC_STRING
54 #define REISERFS_SUPER_MAGIC_STRING "ReIsErFs"
55 #endif
56 #endif
57
58 #ifndef REISERFS_IOC_UNPACK
59 #define REISERFS_IOC_UNPACK             _IOW(0xCD,1,long)
60 #endif
61
62 #ifndef REISER4_SUPER_MAGIC
63 #define REISER4_SUPER_MAGIC  0x52345362
64  /* (*(__u32 *)"R4Sb"); */
65 #endif
66 #ifndef REISER4_IOC_UNPACK
67 #define REISER4_IOC_UNPACK              _IOW(0xCD,1,long)
68 #endif
69 #endif
70
71 #ifdef LCF_DEVMAPPER
72 typedef struct _dm_target {
73     struct _dm_target *next;
74     uint64_t start,length,offset;
75     int device;
76 } DM_TARGET;
77
78 typedef struct _dm_table {
79     struct _dm_table *next;
80     int device;
81     struct _dm_target *target;
82 } DM_TABLE;
83
84 DM_TABLE *dmtab = NULL;
85 int dm_version_nr = 0;
86 #endif
87
88 int dm_major_list[16];
89 int dm_major_nr;
90
91 #ifdef LCF_LVM
92 struct lv_bmap {
93     __u32 lv_block;
94     dev_t lv_dev;                       /* was __u16, which is wrong */
95 };
96
97 #ifndef LV_BMAP
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)  */
102 #endif
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) */
108 #endif
109 #endif
110
111 #ifdef LCF_EVMS
112 struct evms_get_bmap_t {
113     __u64 rsector;
114     __u32 dev;
115     int status;
116 };
117
118 struct evms_version_t {
119     __u32 major;
120     __u32 minor;
121     __u32 patch;
122 };
123
124 #ifndef EVMS_GET_BMAP
125 #define EVMS_GET_BMAP           _IOWR(MAJOR_EVMS, 0xC7, struct evms_get_bmap_t)
126 #endif
127 #ifndef EVMS_GET_IOCTL_VERSION
128 #define EVMS_GET_IOCTL_VERSION  _IOR(MAJOR_EVMS, 0x0, struct evms_version_t)
129 #endif
130 #endif
131
132 #ifndef HDIO_GETGEO
133 #define HDIO_GETGEO HDIO_REQ
134 #endif
135
136
137 typedef struct _st_buf {
138     struct _st_buf *next;
139     struct stat st;
140 } ST_BUF;
141
142
143 DT_ENTRY *disktab = NULL;
144 int old_disktab = 0;
145
146
147 void geo_init(char *name)
148 {
149     FILE *file = NULL;
150     char line[MAX_LINE+1];
151 #ifdef LCF_DEVMAPPER
152     struct dm_task *dmt;
153     char dm_version[32];
154 #endif
155     char major_name[32];
156     int major;
157     char *here;
158     DT_ENTRY *entry;
159     int disk_section,items;
160
161     if (name) {
162         if ((file = fopen(name,"r")) == NULL)
163             die("open %s: %s",name,strerror(errno));
164     }
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');
169             if (here) *here = 0;
170             here = strchr(line,'#');
171             if (here) *here = 0;
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,
176                   &entry->start);
177                 if (items == 5) entry->start = -1;
178                 if (items < 5)
179                     die("Invalid line in %s:\n\"%s\"",name ? name : DFL_DISKTAB,
180                       line);
181                 entry->next = disktab;
182                 disktab = entry;
183                 if (disk_section) die("DISKTAB and DISK are mutually exclusive");
184                 old_disktab = 1;
185             }
186         }
187         (void) fclose(file);
188     }
189
190     dm_major_nr = 0;
191     file = fopen("/proc/devices", "r");
192     if (!file) return;
193
194     do {
195         if (!fgets(line, (sizeof line)-1, file)) {
196             (void) fclose(file);
197             return;
198         }
199         line[(sizeof line)-1] = 0;
200     } while(strncmp(line, "Block", 5) != 0);
201
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;
206         if (verbose >= 3) {
207             printf("device-mapper major = %d\n", major);
208         }
209         if (++dm_major_nr > nelem(dm_major_list) ) break;
210     }
211
212     (void) fclose(file);
213
214
215 #ifdef LCF_DEVMAPPER
216     /* Suppress error message if the device doesn't exist. It is ugly */
217     struct stat fs;
218
219     if (stat ("/dev/mapper/control", &fs))
220         return;
221
222     if (!(dmt = dm_task_create(DM_DEVICE_VERSION)))
223         return;
224     if (!dm_task_run(dmt))
225         return;
226     if (!dm_task_get_driver_version(dmt, dm_version, sizeof dm_version))
227         return;
228
229     /*
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...)
233      */
234     dm_version_nr = atoi(dm_version);
235
236     dm_task_destroy(dmt);
237 #endif
238 }
239
240
241 int is_dm_major(int major)
242 {
243     int i;
244     
245     for(i=0; i<dm_major_nr; i++) {
246         if (dm_major_list[i] == major) return 1;
247     }
248     return 0;
249 }
250
251
252
253 void do_partition(void)
254 {
255     DT_ENTRY *entry,*walk;
256     struct stat st;
257     char *partition,*start;
258
259     entry = alloc_t(DT_ENTRY);
260     *entry = *disktab;
261     entry->start = -1;
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;
275     disktab = entry;
276     cfg_init(cf_partitions);
277 }
278
279 #if BETA_TEST
280 int has_partitions_beta(dev_t dev)
281 {
282     int major = MAJOR(dev);
283     
284     if (
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 */
292       
293     if (
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 */
303
304     if ( major == MAJOR_SATA || major == MAJOR_SATA2
305         )  return 0xFFFFFFE0;   /* 5 bit partition mask */
306
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 */
311
312     return 0;
313 }
314 #endif
315
316 static
317 unsigned char max_partno[512] = {
318 /*
319   0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
320 */
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,
324 #ifndef MAJOR_IDE5
325   7,  7,  7,  7,  7,  7,  7,  7,  0, 63,  0,  0, 15, 15, 15, 15,
326 #else
327   7,  7,  7,  7,  7,  7,  7,  7, 63, 63,  0,  0, 15, 15, 15, 15,
328 #endif
329
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,
334 /*
335   0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
336 */
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,
341
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
346 /*                                                                 
347   0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
348 */
349 };
350
351 int has_partitions(dev_t dev)
352 {
353    int major = MAJOR(dev);
354    int ret=0;
355    
356    if (major >= nelem(max_partno)) {
357         warn("Major Device (%d) > %d",
358                 major, nelem(max_partno)-1);
359    }
360    else if ( (ret=max_partno[major]) )  ret ^= 0xFFFFFFFF;
361    
362    return ret;
363 }
364
365
366 void do_disk(void)
367 {
368     DT_ENTRY *entry,*walk;
369     struct stat st;
370     char *disk,*bios,*sectors,*heads,*cylinders,*maxpart;
371     int major;
372
373     disk = cfg_get_strg(cf_options,"disk");
374     cfg_init(cf_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");
379             return;
380         }
381         die("do_disk: stat %s: %s",disk,strerror(errno));
382     }
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);
386
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");
395     if (maxpart) {
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);
401       }
402       else {
403         die("Implementation restriction: max-partitions on major device > %d", (int)nelem(max_partno)-1);
404       }
405     }
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");
410         else {
411             entry->sectors = to_number(sectors);
412             entry->heads = to_number(heads);
413         }
414     if (cfg_get_flag(cf_disk,"inaccessible")) {
415         entry->heads = 0;
416         if (bios) die("INACCESSIBLE and BIOS are mutually exclusive");
417         if ( sectors || heads || cylinders )
418             die("No geometry variables allowed if INACCESSIBLE");
419     }
420     entry->cylinders = cylinders ? to_number(cylinders) : -1;
421     entry->start = 0;
422     for (walk = disktab; walk; walk = walk->next) {
423         if (entry->device == walk->device)
424             die("Duplicate \"disk =\" definition for %s",disk);
425     }
426     entry->next = disktab;
427     disktab = entry;
428     if (verbose >= 6) {
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);
432     }
433     cfg_init(cf_partitions);
434     (void) cfg_parse(cf_partitions);
435     cfg_unset(cf_options,"disk");
436 }
437
438
439 static int exists(const char *name)
440 {
441     struct hd_geometry dummy;
442     int fd,yes;
443     char buff;
444
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;
447     (void) close(fd);
448     return yes;
449 }
450
451
452 #if 0
453
454 static int scan_last_dev(ST_BUF *next,char *parent,int major,int increment)
455 {
456     DIR *dp;
457     struct dirent *dir;
458     char name[PATH_MAX+1];
459     ST_BUF st,*walk;
460     int max,this;
461
462     st.next = next;
463     max = 0;
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;
473             }
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;
478                 if (!walk) {
479                     this = scan_last_dev(&st,name,major,increment);
480                     if (this > max) max = this;
481                 }
482             }
483         }
484     }
485     (void) closedir(dp);
486     return max;
487 }
488
489 #endif
490
491
492 static int last_dev(int major,int increment)
493 {
494 /*
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.
501  */
502     DEVICE dev;
503     int devs;
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;
509
510
511     for (devs = 0;
512         devs < 2 && dev_open(&dev,MKDEV(major,increment*devs),O_BYPASS);
513             devs++)
514         if (exists(dev.name)) dev_close(&dev);
515         else {
516             dev_close(&dev);
517             break;
518         }
519     cached_result = devs;
520     return devs;
521 }
522
523
524 #ifdef LCF_LVM
525 void lvm_bmap(struct lv_bmap *lbm)
526 {
527     DEVICE dev;
528     static int lvmfd = -1;
529     static dev_t last_dev = 0;
530
531     if (lbm->lv_dev != last_dev) {
532         char lvm_char[] = DEV_DIR "/lvm";
533         unsigned short iop;
534
535         if (lvmfd != -1)
536             close(lvmfd);
537
538         if ((lvmfd = open(lvm_char, lbm->lv_dev, O_RDONLY)) < 0)
539             die("can't open LVM char device %s\n", lvm_char);
540
541         if (ioctl(lvmfd, LVM_GET_IOP_VERSION, &iop) < 0)
542             die("LVM_GET_IOP_VERSION failed on %s\n", lvm_char);
543
544         if (iop < 10)
545             die("LVM IOP %d not supported for booting\n", iop);
546         close(lvmfd);
547
548         lvmfd = dev_open(&dev, lbm->lv_dev, O_RDONLY);
549         if (lvmfd < 0)
550             die("can't open LVM block device %#x\n", (int)lbm->lv_dev);
551         last_dev = lbm->lv_dev;
552     }
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");
556     }
557 }
558 #endif
559
560
561 #ifdef LCF_EVMS
562 void evms_bmap(struct evms_get_bmap_t *ebm)
563 {                                  
564     DEVICE dev;
565     static int evms_fd = -1;
566     static dev_t evms_last_dev = 0;
567
568     if (ebm->dev != evms_last_dev) {
569         char evms_blk[] = DEV_DIR "/evms/block_device";
570         struct evms_version_t evms_ver;
571
572         /* Open the EVMS device */
573         if (evms_fd != -1)
574             close(evms_fd);
575
576         evms_fd = open(evms_blk, O_RDONLY);
577         if (evms_fd < 0)
578             die("Can't open EVMS block device %s.\n", evms_blk);
579
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);
583
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);
589         close(evms_fd);
590
591         evms_fd = dev_open(&dev, ebm->dev, O_RDONLY);
592         if (evms_fd < 0)
593             die("Can't open EVMS block device %#x\n", ebm->dev);
594         evms_last_dev = ebm->dev;
595     }
596
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");
600     }
601 }
602 #endif
603
604
605 void geo_query_dev(GEOMETRY *geo,int device,int all)
606 {
607     DEVICE dev;
608     int fd,get_all,major;
609     struct floppy_struct fdprm;
610     struct hd_geometry hdprm;
611
612     if (verbose>=5) printf("geo_query_dev: device=%04X\n", device);
613 #if 0
614 /*  Werner's original */
615     get_all = all || MAJOR(device) != MAJOR_FD; */
616 #else
617 /* simplify the condition -- JRC 2003-06-04 */
618     get_all = all;
619 #endif
620     if (!MAJOR(device))
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.");
625     if (get_all) {
626         fd = dev_open(&dev,device,O_NOACCESS);
627     }
628     else {
629         fd = -1; /* pacify GCC */
630         geo->heads = geo->cylinders = geo->sectors = 1;
631         geo->start = 0;
632         geo->device = -1;
633     }
634     switch ((major=MAJOR(device))) {
635         case MAJOR_FD:
636             geo->device = device & 3;
637             if (!get_all) break;
638             if (ioctl(fd,FDGETPRM,&fdprm) < 0)
639                 die("geo_query_dev FDGETPRM (dev 0x%04x): %s",device,
640                   strerror(errno));
641             geo->heads = fdprm.head;
642             geo->cylinders = fdprm.track;
643             geo->sectors = fdprm.sect;
644             geo->start = 0;
645             break;
646         case MAJOR_HD:
647         case MAJOR_IDE2:
648         case MAJOR_IDE3:
649         case MAJOR_IDE4:
650 #ifdef MAJOR_IDE5
651         case MAJOR_IDE5:
652 #endif
653         case MAJOR_IDE6:
654         case MAJOR_IDE7:
655         case MAJOR_IDE8:
656         case MAJOR_IDE9:
657         case MAJOR_IDE10:
658         case MAJOR_ESDI:
659         case MAJOR_XT:
660         case MAJOR_ACORN:
661         MASK63:
662             geo->device = 0x80 + (MINOR(device) >> 6) +
663                     (MAJOR(device) == MAJOR_HD ? 0 : last_dev(MAJOR_HD,64));
664             if (!get_all) break;
665             if (ioctl(fd,HDIO_GETGEO,&hdprm) < 0)
666                 die("geo_query_dev HDIO_GETGEO (dev 0x%04x): %s",device,
667                   strerror(errno));
668             geo->heads = hdprm.heads;
669             geo->cylinders = hdprm.cylinders;
670             geo->sectors = hdprm.sectors;
671             geo->start = hdprm.start;
672             break;
673         case MAJOR_SD:
674         case MAJOR_SD2:
675         case MAJOR_SD3:
676         case MAJOR_SD4:
677         case MAJOR_SD5:
678         case MAJOR_SD6:
679         case MAJOR_SD7:
680         case MAJOR_SD8:
681         MASK15:
682             geo->device = 0x80 + last_dev(MAJOR_HD,64) + (MINOR(device) >> 4);
683             if (!get_all) break;
684             if (ioctl(fd,HDIO_GETGEO,&hdprm) < 0)
685                 die("geo_query_dev HDIO_GETGEO (dev 0x%04x): %s",device,
686                   strerror(errno));
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;
694             break;
695         MASK31:
696             geo->device = 0x80 + last_dev(MAJOR_HD,64) + (MINOR(device) >> 5);
697             if (!get_all) break;
698             if (ioctl(fd,HDIO_GETGEO,&hdprm) < 0)
699                 die("geo_query_dev HDIO_GETGEO (dev 0x%04x): %s",device,
700                   strerror(errno));
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;
708             break;
709         case MAJOR_DAC960:
710         case MAJOR_DAC960+1:
711         case MAJOR_DAC960+2:
712         case MAJOR_DAC960+3:
713         case MAJOR_DAC960+4:
714         case MAJOR_DAC960+5:
715         case MAJOR_DAC960+6:
716         case MAJOR_DAC960+7:
717         case MAJOR_IBM_iSER:
718         MASK7:
719             geo->device = 0x80 + last_dev(MAJOR_HD,64) + (MINOR(device) >> 3);
720             if (!get_all) break;
721             if (ioctl(fd,HDIO_GETGEO,&hdprm) < 0)
722                 die("geo_query_dev HDIO_GETGEO (dev 0x%04x): %s",device,
723                   strerror(errno));
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;
731             break;
732         case MAJOR_AMI_HYP:
733         case MAJOR_HPT370:
734         case MAJOR_EXPR:
735         case MAJOR_EXPR+1:
736         case MAJOR_EXPR+2:
737         case MAJOR_EXPR+3:
738         case MAJOR_FTL:
739         case MAJOR_NFTL:
740         case MAJOR_DOC:
741         case MAJOR_SMART2+0:
742         case MAJOR_SMART2+1:
743         case MAJOR_SMART2+2:
744         case MAJOR_SMART2+3:
745         case MAJOR_SMART2+4:
746         case MAJOR_SMART2+5:
747         case MAJOR_SMART2+6:
748         case MAJOR_SMART2+7:
749         case MAJOR_CISS+0:
750         case MAJOR_CISS+1:
751         case MAJOR_CISS+2:
752         case MAJOR_CISS+3:
753         case MAJOR_CISS+4:
754         case MAJOR_CISS+5:
755         case MAJOR_CISS+6:
756         case MAJOR_CISS+7:
757         case MAJOR_I2O:
758         case MAJOR_I2O+1:
759         case MAJOR_I2O+2:
760         case MAJOR_I2O+3:
761         case MAJOR_I2O+4:
762         case MAJOR_I2O+5:
763         case MAJOR_I2O+6:
764         case MAJOR_I2O+7:
765             geo->device = 0x80 + last_dev(MAJOR_HD,64) + (MINOR(device) >> 4);
766             if (!get_all) break;
767             if (ioctl(fd,HDIO_GETGEO,&hdprm) < 0)
768                 die("geo_query_dev HDIO_GETGEO (dev 0x%04x): %s",device,
769                   strerror(errno));
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;
777             break;
778
779         default:
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;
785             
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);
791     }
792     if (get_all) dev_close(&dev);
793     if (verbose>=5) printf("exit geo_query_dev\n");
794 }
795
796
797 int is_first(int device)
798 {
799     DT_ENTRY *walk;
800
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)) {
810         case MAJOR_FD:
811             return !(device & 3);
812
813         case MAJOR_HD:
814             return !(MINOR(device) >> 6);
815
816         case MAJOR_IDE2:
817         case MAJOR_IDE3:
818         case MAJOR_IDE4:
819 #ifdef MAJOR_IDE5
820         case MAJOR_IDE5:
821 #endif
822         case MAJOR_IDE6:
823         case MAJOR_IDE7:
824         case MAJOR_IDE8:
825         case MAJOR_IDE9:
826         case MAJOR_IDE10:
827         case MAJOR_ESDI:
828         case MAJOR_XT:
829             return MINOR(device) >> 6 ? 0 : !last_dev(MAJOR_HD,64);
830
831         case MAJOR_SD:
832         case MAJOR_SD2:
833         case MAJOR_SD3:
834         case MAJOR_SD4:
835         case MAJOR_SD5:
836         case MAJOR_SD6:
837         case MAJOR_SD7:
838         case MAJOR_SD8:
839         case MAJOR_AMI_HYP:
840         case MAJOR_HPT370:
841         case MAJOR_EXPR+0:
842         case MAJOR_EXPR+1:
843         case MAJOR_EXPR+2:
844         case MAJOR_EXPR+3:
845         case MAJOR_NFTL:
846         case MAJOR_DOC:
847         case MAJOR_SMART2+0:
848         case MAJOR_SMART2+1:
849         case MAJOR_SMART2+2:
850         case MAJOR_SMART2+3:
851         case MAJOR_SMART2+4:
852         case MAJOR_SMART2+5:
853         case MAJOR_SMART2+6:
854         case MAJOR_SMART2+7:
855         case MAJOR_CISS+0:
856         case MAJOR_CISS+1:
857         case MAJOR_CISS+2:
858         case MAJOR_CISS+3:
859         case MAJOR_CISS+4:
860         case MAJOR_CISS+5:
861         case MAJOR_CISS+6:
862         case MAJOR_CISS+7:
863         case MAJOR_I2O:
864         case MAJOR_I2O+1:
865         case MAJOR_I2O+2:
866         case MAJOR_I2O+3:
867         case MAJOR_I2O+4:
868         case MAJOR_I2O+5:
869         case MAJOR_I2O+6:
870         case MAJOR_I2O+7:
871             return MINOR(device) >> 4 ? 0 : !last_dev(MAJOR_HD,64);
872
873         case MAJOR_DAC960:
874         case MAJOR_DAC960+1:
875         case MAJOR_DAC960+2:
876         case MAJOR_DAC960+3:
877         case MAJOR_DAC960+4:
878         case MAJOR_DAC960+5:
879         case MAJOR_DAC960+6:
880         case MAJOR_DAC960+7:
881         case MAJOR_IBM_iSER:
882             return MINOR(device) >> 3 ? 0 : !last_dev(MAJOR_HD,64);
883
884         default:
885             return 1; /* user knows what (s)he's doing ... I hope */
886     }
887 }
888
889
890 void geo_get(GEOMETRY *geo,int device,int user_device,int all)
891 {
892     DT_ENTRY *walk;
893     int inherited,keep_cyls,is_raid=0;
894 #ifdef LCF_DEVMAPPER
895     int i;
896
897     for(i = 0; i < dm_major_nr; i++)
898         if (MAJOR(device) == dm_major_list[i])
899             break;
900     while (i < dm_major_nr) {
901         DM_TABLE *dm_table;
902
903         for(dm_table = dmtab; dm_table; dm_table = dm_table->next)
904             if (dm_table->device == device)
905                 break;
906
907         if (dm_table) {
908             DM_TARGET *target;
909
910              device = 0;
911             for(target = dm_table->target; target; target = target->next)
912                 device = target->device;
913         } else {
914             DEVICE dev;
915             struct dm_task *dmt;
916             void *next = NULL;
917             char dmdev[PATH_MAX+1];
918             char buf[PATH_MAX+1];
919             char *slash;
920             int result;
921
922             dev_open(&dev, device, -1);
923             strncpy(dmdev, dev.name, PATH_MAX);
924             dmdev[PATH_MAX] = 0;
925             do {
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,
929                         strerror(errno));
930                 if (result >= 0) {
931                     if (buf[0] != '/' && (slash = strrchr(dmdev, '/')) != NULL)
932                         slash++;
933                     else
934                         slash = dmdev;
935                     strncpy(slash, buf, PATH_MAX - (slash-dmdev));
936                 }
937                 if (realpath(dmdev, buf) == NULL)
938                     die("device-mapper: realpath(\"%s\") failed with: %s",dmdev,
939                         strerror(errno));
940                 strncpy(dmdev, buf, PATH_MAX);
941             } while (result >= 0);
942             dmdev[PATH_MAX] = 0;
943
944             if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
945                 die("device-mapper: dm_task_create(DM_DEVICE_TABLE) failed");
946             slash = strrchr(dmdev, '/');
947                 if (slash)
948             slash++;
949                 else
950             slash = 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");
956
957             dm_table = alloc_t(DM_TABLE);
958             dm_table->device = device;
959             dm_table->target = NULL;
960             dm_table->next = dmtab;
961             dmtab = dm_table;
962
963             device = 0;
964
965             do {
966                 DM_TARGET *target;
967                 uint64_t start,length;
968                 int major,minor;
969                 char *target_type,*params;
970                 char *p;
971
972                 next = dm_get_next_target(dmt, next, &start, &length,
973                   &target_type, &params);
974
975                 if (!target_type) continue;
976
977                 if (strcmp(target_type, "linear") != 0)
978                     die("device-mapper: only linear boot device supported");
979
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]) &&
986                     params[2] == ':' &&
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 */
996                     struct stat st;
997                     FILE *file;
998
999                     p = strrchr(params, ' ');
1000                     if (p == NULL)
1001                         die("device-mapper: parse error in linear params (\"%s\")", params);
1002                     *p = 0;
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 */
1010                         int dev;
1011                         sprintf(buf, "/sys/block/%s/dev", params);
1012                         file = fopen(buf, "r");
1013                         if (!file)
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);
1020                             major = MAJOR(dev);
1021                             minor = MINOR(dev);
1022                         }
1023                         (void) fclose(file);
1024                     }
1025                     *p = ' ';
1026                     if (sscanf(p+1, "%"PRIu64, &target->offset) != 1)
1027                         die("device-mapper: parse error in linear params (\"%s\")", params);
1028                 }
1029                 target->device = (major << 8) | minor;
1030                 if (!device)
1031                     device = target->device;
1032                 target->next = dm_table->target;
1033                 dm_table->target = target;
1034             } while(next);
1035
1036             dm_task_destroy(dmt);
1037
1038             dev_close(&dev);
1039         }
1040
1041         if (!device)
1042             die("device-mapper: Error finding real device");
1043         geo->base_dev = device;
1044
1045         for(i = 0; i < dm_major_nr; i++)
1046             if (MAJOR(device) == dm_major_list[i])
1047                 break;
1048     }
1049 #endif
1050
1051     if (verbose>=5) printf("geo_get: device %04X, all=%d\n", device, all);
1052 #ifdef LCF_LVM
1053     /*
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.
1058      *
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).
1064      */
1065     if (MAJOR(device) == MAJOR_LVM)
1066     {
1067         struct lv_bmap lbmA, lbmB;
1068 #define DIFF 255
1069
1070         lbmA.lv_dev = lbmB.lv_dev = device;
1071         lbmA.lv_block = 0;
1072         lbmB.lv_block = DIFF;
1073
1074         lvm_bmap(&lbmA);
1075         lvm_bmap(&lbmB);
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;
1079     }
1080 #endif
1081
1082 #ifdef LCF_EVMS
1083     if (MAJOR(device) == MAJOR_EVMS) {
1084         struct evms_get_bmap_t ebm;
1085         
1086         ebm.rsector = 0;
1087         ebm.dev = device;
1088         ebm.status = 0;
1089         
1090         evms_bmap(&ebm);
1091         
1092         device = geo->base_dev = ebm.dev;
1093     }
1094 #endif
1095
1096     /* Find underlying device for MD RAID */
1097     if (MAJOR(device) == MD_MAJOR) {
1098         char mdxxx[16];
1099         int md_fd;
1100 /*      int pass;       */
1101         struct md_version md_version_info;
1102         md_array_info_t md_array_info;
1103         md_disk_info_t md_disk_info;
1104         int raid_limit;
1105
1106         sprintf(mdxxx, DEV_DISK_DIR "/md%d", MINOR(device));
1107         if ((md_fd=open(mdxxx,O_NOACCESS)) < 0)
1108         {
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);
1112         }
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");
1119         
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))
1127             ) {
1128             die("Incompatible Raid version information on %s   (RV=%d.%d GAI=%d.%d)",
1129                 mdxxx,
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);
1134             }
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;
1138
1139         /* version 22.7 */
1140 #if 1
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);
1146
1147 #else           /* prior to 22.7 */
1148 {
1149 int pass;
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)
1153 #if BETA_TEST
1154             {
1155                 printf("(raid) GET_DISK_INFO: failed for pass=%d\n", pass);
1156                 continue;
1157             }
1158 #else
1159                 die("GET_DISK_INFO: %s", mdxxx);
1160 #endif
1161             if (!(md_disk_info.state & (1 << MD_DISK_FAULTY))) {
1162 #if 1
1163                 is_raid = (device==boot_dev_nr);
1164 #else
1165 /* this change may be in error; the correct comparison is == */
1166                 is_raid = (device!=boot_dev_nr);
1167 #endif
1168                 device = MKDEV(md_disk_info.major, md_disk_info.minor);
1169                 break;
1170             }
1171         }
1172 }
1173 #endif  /* end of code prior to version 22.7 */
1174
1175         close(md_fd);
1176     }
1177
1178 #if BETA_TEST
1179         if (verbose>=5) printf("geo_get(2):  device=%04X, all=%d\n", device, all);
1180 #endif
1181
1182 /* if using hard disk, scan the devices in /proc/partitions */
1183     if (has_partitions(device) && all)   pf_hard_disk_scan();
1184
1185
1186
1187
1188     for (walk = disktab; walk; walk = walk->next)
1189         if (walk->device == device) break;
1190     inherited = !walk && !old_disktab;
1191 #if BETA_TEST
1192     if (verbose>=5) printf("inherited=%d\n", inherited);
1193 #endif
1194     if (inherited)
1195         for (walk = disktab; walk; walk = walk->next)
1196             if (walk->device == (device & D_MASK(device))) break;
1197 #if BETA_TEST
1198     if (verbose>=5) printf("walk=%08lx\n", (long)walk);
1199 #endif
1200
1201 #if 1
1202 /* add 'all' to conditional below -- JRC 2002-08-20 */
1203     if (walk && !walk->heads && all)
1204 #else
1205 /* Werner's original conditional */
1206     if (walk && !walk->heads)
1207 #endif
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;
1211 #if BETA_TEST
1212     if (verbose>=5) printf("inherited=%d  keep_cyls=%d\n", inherited, keep_cyls);
1213 #endif
1214
1215 #if 1
1216 /* add 'all' to conditional below -- JRC 2002-08-20 */
1217     if (keep_cyls && (all || MAJOR(device)==MAJOR_FD) ) {
1218 #else
1219 /* Werner's original conditional */
1220     if (keep_cyls) {
1221 #endif
1222         geo_query_dev(geo,device,all);
1223         
1224         if (all) bios_device(geo, device);
1225         
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",
1229               geo->device);
1230     }
1231     if (walk) {
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;
1238     }
1239     if (user_device != -1) geo->device = user_device;
1240     if (!all) {
1241         if (verbose > 2)
1242             printf("Device 0x%04x: BIOS drive 0x%02x, no geometry.\n",device,
1243               geo->device);
1244         return;
1245     }
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);
1261     if (!lba32 &&
1262       (geo->start+geo->sectors-1)/geo->heads/geo->sectors >= BIOS_MAX_CYLS
1263     ) {
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);
1267     }
1268     if (verbose >= 3) {
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 :
1271           geo->cylinders);
1272         printf("%15s%d sectors. Partition offset: %d sectors.\n","",
1273           geo->sectors,geo->start);
1274     }
1275     geo->raid = is_raid;
1276
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 */
1280     
1281     return;
1282 } /* end of geo_get */
1283
1284
1285 int geo_open(GEOMETRY *geo,const char *name,int flags)
1286 {
1287     char *here;
1288     int user_dev,block_size;
1289     struct stat st;
1290
1291     if ((here = strrchr(name,':')) == NULL) user_dev = -1;
1292     else {
1293         *here++ = 0;
1294         warn("%s:BIOS syntax is no longer supported.\n    Please use a "
1295           "DISK section.", name);
1296         user_dev = to_number(here);
1297     }
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;
1304 #if BETA_TEST
1305         if (verbose>=4) {
1306                 printf("geo_open: (%s) st_dev(file)=%04X  st_rdev(blk)=%04X\n",
1307                 name,
1308                 (int)st.st_dev,
1309                 (int)st.st_rdev );
1310         }
1311 #endif
1312
1313     geo_get(geo, geo->dev, user_dev, 1);
1314     geo->file = S_ISREG(st.st_mode) ? st.st_dev : 0;
1315     geo->boot = 0;
1316 #ifndef FIGETBSZ
1317     geo->spb = 2;
1318 #else
1319     if (!geo->file) geo->spb = 2;
1320     else {
1321         if (ioctl(geo->fd,FIGETBSZ,&block_size) < 0) {
1322             warn("FIGETBSZ %s: %s",name,strerror(errno));
1323             geo->spb = 2;
1324         }
1325         else {
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;
1329         }
1330     }
1331 #endif
1332     return geo->fd;
1333 }
1334
1335
1336 int geo_open_boot(GEOMETRY *geo,char *name)
1337 {
1338     struct stat st;
1339
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;
1345 #if 1
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));
1349 #else
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");
1353     }
1354     geo->fd = 0;
1355 #endif
1356     geo_get(geo, geo->dev, -1, 0);
1357     geo->file = S_ISREG(st.st_mode);
1358     geo->raid = 0;
1359     geo->boot = 1;
1360     geo->spb = 1;
1361     return geo->fd;
1362 }
1363
1364
1365 void geo_close(GEOMETRY *geo)
1366 {
1367     if (geo->fd) (void) close(geo->fd);
1368     geo->fd = 0;
1369 }
1370
1371
1372 #ifndef FIBMAP
1373 #define FIBMAP BMAP_IOCTL
1374 #endif
1375
1376
1377 int geo_comp_addr(GEOMETRY *geo,int offset,SECTOR_ADDR *addr)
1378 {
1379     int block,sector;
1380     static int linear_warnings = 0;
1381
1382 #if BETA_TEST
1383     if (verbose>=6)
1384         printf("geo_comp_addr: dev = %x, offset=%d\n",
1385                 geo->device, offset);
1386 #endif
1387
1388 #if 0
1389     if (linear && lba32)
1390        die("'linear' and 'lba32' (-l and -L) are mutually exclusive.");
1391 #endif
1392     if (geo->boot && offset >= SECTOR_SIZE)
1393         die("Internal error: sector > 0 after geo_open_boot");
1394     block = offset/geo->spb/SECTOR_SIZE;
1395     if (geo->file) {
1396 #ifdef LCF_REISERFS
1397             struct statfs buf;
1398
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);
1404             }
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);
1410
1411            /* 
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.
1417            */
1418                 if (fdatasync(geo->fd) != 0)
1419                     die("Cannot perform fdatasync");
1420            
1421                 if (verbose > 3) printf("fd %d: fdatasync()\n", geo->fd);
1422            }
1423 #endif
1424         if (ioctl(geo->fd,FIBMAP,&block) < 0) pdie("ioctl FIBMAP");
1425         if (!block) {
1426             return 0;
1427         }
1428     }
1429 #ifdef LCF_LVM
1430     if (MAJOR(geo->dev) == MAJOR_LVM) {
1431         struct lv_bmap lbm;
1432
1433         lbm.lv_dev = geo->dev;
1434         lbm.lv_block = block;
1435
1436         lvm_bmap(&lbm);
1437         if (lbm.lv_dev != geo->base_dev)
1438             die("LVM boot LV cannot be on multiple PVs\n");
1439         block = lbm.lv_block;
1440     }
1441 #endif
1442
1443 #ifdef LCF_EVMS
1444     if (MAJOR(geo->dev) == MAJOR_EVMS) {
1445         struct evms_get_bmap_t ebm;
1446                           
1447         ebm.rsector = block * geo->spb;
1448         ebm.dev = geo->dev;
1449         ebm.status = 0;
1450                             
1451         evms_bmap(&ebm);
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;
1455     }
1456     else
1457 #endif
1458     {
1459 #ifdef LCF_DEVMAPPER 
1460         int dev = geo->dev;
1461         int i;
1462 #endif
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])
1467                 break;
1468         while (i < dm_major_nr) {
1469             DM_TABLE *dm_table;
1470             DM_TARGET *dm_target;
1471
1472             for(dm_table = dmtab; dm_table; dm_table = dm_table->next)
1473                 if (dm_table->device == dev)
1474                     break;
1475             if (!dm_table)
1476                 die("device-mapper: Mapped device suddenly lost? (%d)", dev);
1477
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))
1480                     break;
1481             if (!dm_target)
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));
1485
1486             dev = dm_target->device;
1487             sector = dm_target->offset+(sector-dm_target->start);
1488
1489             for(i = 0; i < dm_major_nr; i++)
1490                 if (MAJOR(dev) == dm_major_list[i])
1491                     break;
1492         }
1493
1494         if (dev != geo->dev && dev != geo->base_dev)
1495             die("device-mapper: mapped boot device cannot be on multiple real devices\n");
1496 #endif
1497         sector += geo->start;
1498     }
1499
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))
1504 #if 0
1505                 | (do_md_install && geo->file==boot_dev_nr ? RAID_REL_FLAG : 0);
1506 #else
1507                 | (do_md_install && geo->raid ? RAID_REL_FLAG : 0);
1508 #endif
1509         addr->num_sect = linear ? 1 : (sector >> 24);
1510         addr->sector = sector & 0xff;
1511         addr->track = (sector >> 8) & 0xff;
1512         addr->head = sector >> 16;
1513         if (linear) {
1514             int cyl = sector;
1515             if (geo->sectors>0 && geo->heads>0) {
1516                 cyl /= geo->sectors;
1517                 cyl /= geo->heads;
1518                 if (cyl >= BIOS_MAX_CYLS && linear_warnings++ < 8) {
1519                     warn("LINEAR may generate cylinder# above 1023 at boot-time.");
1520                 }
1521             }
1522             if (sector/(63*255) >= BIOS_MAX_CYLS)
1523                 die("Sector address %d too large for LINEAR"
1524                                         " (try LBA32 instead).", sector);
1525         }
1526         if (verbose > 4)
1527             printf("fd %d: offset %d -> dev 0x%02x, %s %d\n",
1528                          geo->fd, offset, addr->device,
1529                          lba32 ? "LBA" : "linear",
1530                          sector);
1531     }
1532     else {
1533         addr->device = geo->device;
1534         addr->sector = 1;
1535         addr->head = 0;
1536         if (sector) {
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;
1543         }
1544         if (sector >= BIOS_MAX_CYLS)
1545             die("geo_comp_addr: Cylinder number is too big (%d > %d)",sector,
1546               BIOS_MAX_CYLS-1);
1547         if (sector >= geo->cylinders && geo->cylinders != -1)
1548             die("geo_comp_addr: Cylinder %d beyond end of media (%d)",sector,
1549               geo->cylinders);
1550         if (verbose > 4)
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;
1555         addr->num_sect = 1;
1556     }
1557
1558     return 1;
1559 }
1560
1561
1562 int geo_find(GEOMETRY *geo,SECTOR_ADDR addr)
1563 {
1564     SECTOR_ADDR here;
1565     struct stat st;
1566     int i;
1567
1568 #if DEBUG_NEW
1569     if (verbose>=2) {
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) );
1575     }
1576 #endif
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;
1585                 else return 1;
1586             }
1587     return 1;
1588 }
1589
1590
1591 #if 0
1592 int geo_devscan(int device)
1593 {
1594     DT_ENTRY *walk;
1595     unsigned int mask, codes = 0;
1596     int bios;
1597     int maxbios = 0;
1598     
1599     device &= D_MASK(device);
1600
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);
1606             codes |= 1 << bios; 
1607         }
1608     }
1609
1610     bios = -1;
1611 /* extract BIOS code of master device, or -1 */
1612     for (walk=disktab; walk; walk=walk->next) {
1613         if (device == walk->device) {
1614             bios = walk->bios;
1615         }
1616     }
1617     if (bios > maxbios) maxbios = bios;
1618
1619 /* if device has no BIOS code assigned, assign the next one */
1620     if (bios == -1)
1621         for (bios=0x80, mask=1; mask; mask<<=1, bios++)
1622                 if (!(mask&codes)) break;
1623     
1624     if (bios > DEV_MASK) die("geo_devscan:  ran out of device codes");
1625     
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;
1630             break;
1631         }
1632     }
1633     if (bios > maxbios) maxbios = bios;
1634     
1635     if (verbose >= 2) printf("geo_devscan:  maxbios = %02X\n", maxbios);
1636     
1637     if (walk) return maxbios;   /* there was an entry in the disktab */
1638     
1639     walk = alloc_t(DT_ENTRY);
1640     walk->device = device;
1641     walk->bios = bios;
1642     walk->sectors = walk->heads = walk->cylinders = walk->start = -1;
1643     walk->next = disktab;
1644     disktab = walk;
1645     if (verbose>=2)
1646         printf("geo_devscan: arbitrary bios assignment  dev=%04X  bios=0x%02X\n",
1647                         device, bios);
1648
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;
1652         }
1653     }
1654
1655     return maxbios;
1656 }
1657
1658 #endif
1659