Imported Upstream version 24.0
[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  * Copyright 2009-2011 Joachim Wiedorn
6  * All rights reserved.
7  * 
8  * Licensed under the terms contained in the file 'COPYING'
9  * in the source directory.
10  */
11
12 #define _GNU_SOURCE
13 #include <unistd.h>
14 #include <stdio.h>
15 #include <fcntl.h>
16 #include <errno.h>
17 #include <stdlib.h>
18 #include <limits.h>
19 #include <ctype.h>
20 #include <sys/types.h>
21
22 #ifdef LCF_REISERFS
23 #include <sys/statfs.h>
24
25 #ifdef  _SYS_STATFS_H
26 #define _I386_STATFS_H  /* two versions of statfs is not good ... */
27 #endif
28 #endif
29
30 #include <string.h>
31
32
33 #include "config.h"
34 #ifdef LCF_DEVMAPPER
35 # include <libdevmapper.h>
36 #endif
37 #include "lilo.h"
38 #include "common.h"
39 #include "device.h"
40 #include "raid.h"
41 #include "geometry.h"
42 #include "cfg.h"
43 #include "md-int.h"
44 #include "probe.h"
45
46 #ifdef LCF_REISERFS
47 #ifndef REISERFS_SUPER_MAGIC
48 #define REISERFS_SUPER_MAGIC 0x52654973
49 #endif
50
51 #if 0
52 #ifndef REISERFS_SUPER_MAGIC_STRING
53 #define REISERFS_SUPER_MAGIC_STRING "ReIsErFs"
54 #endif
55 #endif
56
57 #ifndef REISERFS_IOC_UNPACK
58 #define REISERFS_IOC_UNPACK             _IOW(0xCD,1,long)
59 #endif
60
61 #ifndef REISER4_SUPER_MAGIC
62 #define REISER4_SUPER_MAGIC  0x52345362
63  /* (*(__u32 *)"R4Sb"); */
64 #endif
65 #ifndef REISER4_IOC_UNPACK
66 #define REISER4_IOC_UNPACK      _IOW(0xCD,1,long)
67 #endif
68 #endif
69
70 #ifdef LCF_DEVMAPPER
71 typedef struct _dm_target {
72     struct _dm_target *next;
73     uint64_t start,length,offset;
74     int device;
75 } DM_TARGET;
76
77 typedef struct _dm_table {
78     struct _dm_table *next;
79     int device;
80     struct _dm_target *target;
81 } DM_TABLE;
82
83 DM_TABLE *dmtab = NULL;
84 int dm_version_nr = 0;
85 #endif
86
87 int dm_major_list[16];
88 int dm_major_nr;
89
90 #ifdef LCF_LVM
91 struct lv_bmap {
92     __u32 lv_block;
93     dev_t lv_dev;                       /* was __u16, which is wrong */
94 };
95
96 #ifndef LV_BMAP
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)  */
101 #endif
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) */
107 #endif
108 #endif
109
110 #ifdef LCF_EVMS
111 struct evms_get_bmap_t {
112     __u64 rsector;
113     __u32 dev;
114     int status;
115 };
116
117 struct evms_version_t {
118     __u32 major;
119     __u32 minor;
120     __u32 patch;
121 };
122
123 #ifndef EVMS_GET_BMAP
124 #define EVMS_GET_BMAP           _IOWR(MAJOR_EVMS, 0xC7, struct evms_get_bmap_t)
125 #endif
126 #ifndef EVMS_GET_IOCTL_VERSION
127 #define EVMS_GET_IOCTL_VERSION  _IOR(MAJOR_EVMS, 0x0, struct evms_version_t)
128 #endif
129 #endif
130
131 #ifndef HDIO_GETGEO
132 #define HDIO_GETGEO HDIO_REQ
133 #endif
134
135
136 typedef struct _st_buf {
137     struct _st_buf *next;
138     struct stat st;
139 } ST_BUF;
140
141
142 DT_ENTRY *disktab = NULL;
143 int old_disktab = 0;
144
145
146 void geo_init(char *name)
147 {
148     FILE *file = NULL;
149     char line[MAX_LINE+1];
150 #ifdef LCF_DEVMAPPER
151     struct dm_task *dmt;
152     char dm_version[32];
153 #endif
154     char major_name[32];
155     int major;
156     char *here;
157     DT_ENTRY *entry;
158     int disk_section,items;
159
160     if (name) {
161         if ((file = fopen(name,"r")) == NULL)
162             die("open %s: %s",name,strerror(errno));
163     }
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');
168             if (here) *here = 0;
169             here = strchr(line,'#');
170             if (here) *here = 0;
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,
175                   &entry->start);
176                 if (items == 5) entry->start = -1;
177                 if (items < 5)
178                     die("Invalid line in %s:\n\"%s\"",name ? name : DFL_DISKTAB,
179                       line);
180                 entry->next = disktab;
181                 disktab = entry;
182                 if (disk_section) die("DISKTAB and DISK are mutually exclusive");
183                 old_disktab = 1;
184             }
185         }
186         (void) fclose(file);
187     }
188
189     dm_major_nr = 0;
190     file = fopen("/proc/devices", "r");
191     if (!file) return;
192
193     do {
194         if (!fgets(line, (sizeof line)-1, file)) {
195             (void) fclose(file);
196             return;
197         }
198         line[(sizeof line)-1] = 0;
199     } while(strncmp(line, "Block", 5) != 0);
200
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;
205         if (verbose >= 3) {
206             printf("device-mapper major = %d\n", major);
207         }
208         if (++dm_major_nr > nelem(dm_major_list) ) break;
209     }
210
211     (void) fclose(file);
212
213
214 #ifdef LCF_DEVMAPPER
215     /* Suppress error message if the device doesn't exist. It is ugly */
216     struct stat fs;
217
218     if (stat ("/dev/mapper/control", &fs))
219         return;
220
221     if (!(dmt = dm_task_create(DM_DEVICE_VERSION)))
222         return;
223     if (!dm_task_run(dmt))
224         return;
225     if (!dm_task_get_driver_version(dmt, dm_version, sizeof dm_version))
226         return;
227
228     /*
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...)
232      */
233     dm_version_nr = atoi(dm_version);
234
235     dm_task_destroy(dmt);
236 #endif
237 }
238
239
240 int is_dm_major(int major)
241 {
242     int i;
243     
244     for(i=0; i<dm_major_nr; i++) {
245         if (dm_major_list[i] == major) return 1;
246     }
247     return 0;
248 }
249
250
251
252 void do_partition(void)
253 {
254     DT_ENTRY *entry,*walk;
255     struct stat st;
256     char *partition,*start;
257
258     entry = alloc_t(DT_ENTRY);
259     *entry = *disktab;
260     entry->start = -1;
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;
274     disktab = entry;
275     cfg_init(cf_partitions);
276 }
277
278 #if BETA_TEST
279 int has_partitions_beta(dev_t dev)
280 {
281     int major = MAJOR(dev);
282     
283     if (
284       major == MAJOR_HD || major == MAJOR_IDE2 ||
285       major == MAJOR_IDE3 || major == MAJOR_IDE4 ||
286       major == MAJOR_IDE5 || major == MAJOR_IDE6 ||
287       major == MAJOR_EMD  ||
288       (major >= MAJOR_IDE7 && major <= MAJOR_IDE10) ||
289       major == MAJOR_XT || major == MAJOR_ESDI || major == MAJOR_ACORN
290         ) return 0xFFFFFFC0;    /* 6 bit partition mask */
291       
292     if (
293       major == MAJOR_SD || (major >= MAJOR_SD2 && major <= MAJOR_SD8) ||
294       major == MAJOR_AMI_HYP || major == MAJOR_HPT370 ||
295       (major >= MAJOR_EXPR && major <= MAJOR_EXPR+3) ||
296       (major >= MAJOR_I2O && major <= MAJOR_I2O+7) ||
297       (major >= MAJOR_SMART2 && major <= MAJOR_SMART2+7) ||
298       (major >= MAJOR_CISS && major <= MAJOR_CISS+7) ||
299       major == MAJOR_FTL || major == MAJOR_NFTL || major == MAJOR_DOC ||
300       (major >= MAJOR_SD9 && major <= MAJOR_SD16) ||
301       (major >= MAJOR_SATA1 && major <= MAJOR_SATA2)
302         ) return 0xFFFFFFF0;    /* 4 bit partition mask */
303
304     if ( major == MAJOR_CARM1 || major == MAJOR_CARM2
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 && i!=128) 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  * Since last_dev is only used to count IDE drives anyway, we try 
496  * now only the first two devices and forget about scan_last_dev.
497  */
498     DEVICE dev;
499     int devs;
500     static int cached_major=-1, cached_increment=-1, cached_result=-1;
501     if(major == cached_major && increment == cached_increment)
502         return cached_result;
503     cached_major = major;
504     cached_increment = increment;
505
506
507     for (devs = 0;
508         devs < 2 && dev_open(&dev,MKDEV(major,increment*devs),O_BYPASS);
509             devs++)
510         if (exists(dev.name)) dev_close(&dev);
511         else {
512             dev_close(&dev);
513             break;
514         }
515     cached_result = devs;
516     return devs;
517 }
518
519
520 #ifdef LCF_LVM
521 void lvm_bmap(struct lv_bmap *lbm)
522 {
523     DEVICE dev;
524     static int lvmfd = -1;
525     static dev_t last_dev = 0;
526
527     if (lbm->lv_dev != last_dev) {
528         char lvm_char[] = DEV_DIR "/lvm";
529         unsigned short iop;
530
531         if (lvmfd != -1)
532             close(lvmfd);
533
534         if ((lvmfd = open(lvm_char, lbm->lv_dev, O_RDONLY)) < 0)
535             die("can't open LVM char device %s\n", lvm_char);
536
537         if (ioctl(lvmfd, LVM_GET_IOP_VERSION, &iop) < 0)
538             die("LVM_GET_IOP_VERSION failed on %s\n", lvm_char);
539
540         if (iop < 10)
541             die("LVM IOP %d not supported for booting\n", iop);
542         close(lvmfd);
543
544         lvmfd = dev_open(&dev, lbm->lv_dev, O_RDONLY);
545         if (lvmfd < 0)
546             die("can't open LVM block device %#x\n", (int)lbm->lv_dev);
547         last_dev = lbm->lv_dev;
548     }
549     if (ioctl(lvmfd, LV_BMAP, lbm) < 0) {
550         perror(__FUNCTION__);
551         pdie("LV_BMAP error or ioctl unsupported, can't have image in LVM.\n");
552     }
553 }
554 #endif
555
556
557 #ifdef LCF_EVMS
558 void evms_bmap(struct evms_get_bmap_t *ebm)
559 {                                  
560     DEVICE dev;
561     static int evms_fd = -1;
562     static dev_t evms_last_dev = 0;
563
564     if (ebm->dev != evms_last_dev) {
565         char evms_blk[] = DEV_DIR "/evms/block_device";
566         struct evms_version_t evms_ver;
567
568         /* Open the EVMS device */
569         if (evms_fd != -1)
570             close(evms_fd);
571
572         evms_fd = open(evms_blk, O_RDONLY);
573         if (evms_fd < 0)
574             die("Can't open EVMS block device %s.\n", evms_blk);
575
576         /* Get EVMS ioctl version number. */
577         if (ioctl(evms_fd, EVMS_GET_IOCTL_VERSION, &evms_ver) < 0)
578             die("EVMS_GET_IOCTL_VERSION failed on %s.\n", evms_blk);
579
580         /* Check that the ioctl version is >= 7.1.0 */
581         if (evms_ver.major < 7 ||
582             (evms_ver.major == 7 && evms_ver.minor < 1))
583             die("EVMS ioctl version %d.%d.%d does not support booting.\n",
584                 evms_ver.major, evms_ver.minor, evms_ver.patch);
585         close(evms_fd);
586
587         evms_fd = dev_open(&dev, ebm->dev, O_RDONLY);
588         if (evms_fd < 0)
589             die("Can't open EVMS block device %#x\n", ebm->dev);
590         evms_last_dev = ebm->dev;
591     }
592
593     if (ioctl(evms_fd, EVMS_GET_BMAP, ebm) < 0) {
594         perror(__FUNCTION__);
595         pdie("EVMS_GET_BMAP error or ioctl unsupported. Can't have image on EVMS volume.\n");
596     }
597 }
598 #endif
599
600
601 void geo_query_dev(GEOMETRY *geo,int device,int all)
602 {
603     DEVICE dev;
604     int fd,get_all,major;
605     struct floppy_struct fdprm;
606     struct hd_geometry hdprm;
607
608     if (verbose>=5) printf("geo_query_dev: device=%04X\n", device);
609     /* simplified condition -- JRC 2003-06-04 */
610     get_all = all;
611
612     if (!MAJOR(device))
613         die("Trying to map files from unnamed device 0x%04x (NFS/RAID mirror down ?)",device);
614     if (device == MAJMIN_RAM)
615         die("Trying to map files from your RAM disk. "
616           "Please check -r option or ROOT environment variable.");
617     if (get_all) {
618         fd = dev_open(&dev,device,O_NOACCESS);
619     }
620     else {
621         fd = -1; /* pacify GCC */
622         geo->heads = geo->cylinders = geo->sectors = 1;
623         geo->start = 0;
624         geo->device = -1;
625     }
626     switch ((major=MAJOR(device))) {
627         case MAJOR_FD:
628             geo->device = device & 3;
629             if (!get_all) break;
630             if (ioctl(fd,FDGETPRM,&fdprm) < 0)
631                 die("geo_query_dev FDGETPRM (dev 0x%04x): %s",device,
632                   strerror(errno));
633             geo->heads = fdprm.head;
634             geo->cylinders = fdprm.track;
635             geo->sectors = fdprm.sect;
636             geo->start = 0;
637             break;
638         case MAJOR_HD:
639         case MAJOR_IDE2:
640         case MAJOR_IDE3:
641         case MAJOR_IDE4:
642 #ifdef MAJOR_IDE5
643         case MAJOR_IDE5:
644 #endif
645         case MAJOR_IDE6:
646         case MAJOR_IDE7:
647         case MAJOR_IDE8:
648         case MAJOR_IDE9:
649         case MAJOR_IDE10:
650         case MAJOR_ESDI:
651         case MAJOR_XT:
652         case MAJOR_ACORN:
653         MASK63:
654             geo->device = 0x80 + (MINOR(device) >> 6) +
655                     (MAJOR(device) == MAJOR_HD ? 0 : last_dev(MAJOR_HD,64));
656             if (!get_all) break;
657             if (ioctl(fd,HDIO_GETGEO,&hdprm) < 0)
658                 die("geo_query_dev HDIO_GETGEO (dev 0x%04x): %s",device,
659                   strerror(errno));
660             geo->heads = hdprm.heads;
661             geo->cylinders = hdprm.cylinders;
662             geo->sectors = hdprm.sectors;
663             geo->start = hdprm.start;
664             break;
665         case MAJOR_SD:
666         case MAJOR_SD2:
667         case MAJOR_SD3:
668         case MAJOR_SD4:
669         case MAJOR_SD5:
670         case MAJOR_SD6:
671         case MAJOR_SD7:
672         case MAJOR_SD8:
673         MASK15:
674             geo->device = 0x80 + last_dev(MAJOR_HD,64) + (MINOR(device) >> 4);
675             if (!get_all) break;
676             if (ioctl(fd,HDIO_GETGEO,&hdprm) < 0)
677                 die("geo_query_dev HDIO_GETGEO (dev 0x%04x): %s",device,
678                   strerror(errno));
679             if (all && !hdprm.sectors)
680                 die("HDIO_REQ not supported for your SCSI controller. Please "
681                   "use a DISK section");
682             geo->heads = hdprm.heads;
683             geo->cylinders = hdprm.cylinders;
684             geo->sectors = hdprm.sectors;
685             geo->start = hdprm.start;
686             break;
687         case MAJOR_SATA1:
688         case MAJOR_SATA2:
689                 printf("WARNING: SATA partition in the high region (>15):\n");
690                 printf("LILO needs the kernel in one of the first 15 SATA partitions. If \n");
691                 printf("you need support for kernel in SATA partitions of the high region \n");
692                 printf("than try grub2 for this purpose! \n");
693                 die("Sorry, cannot handle device 0x%04x",device);
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                     (int) 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