📄 geometry.c
字号:
/* geometry.c - Device and file geometry computation *//*Copyright 1992-1998 Werner Almesberger.Copyright 1999-2001 John Coffman.All rights reserved.Licensed under the terms contained in the file 'COPYING' in the source directory.*//* Patched for linux-2.4.0 - Glibc-2.2 by Sergey Ostrovsky 11/16/2000 */#include <unistd.h>#include <stdio.h>#include <fcntl.h>#include <errno.h>#include <sys/types.h>#ifdef LCF_REISERFS#include <sys/statfs.h>#ifdef _SYS_STATFS_H#define _I386_STATFS_H /* two versions of statfs is not good ... */#endif#endif#include <linux/fs.h>#include <linux/hdreg.h>#include <linux/fd.h>#include <string.h>#include "config.h"#include "lilo.h"#include "common.h"#include "device.h"#include "geometry.h"#include "cfg.h"#include "md-int.h"#include "probe.h"#ifdef LCF_REISERFS#ifndef REISERFS_SUPER_MAGIC#define REISERFS_SUPER_MAGIC 0x52654973#endif#ifndef REISERFS_SUPER_MAGIC_STRING#define REISERFS_SUPER_MAGIC_STRING "ReIsErFs"#endif#ifndef REISERFS_IOC_UNPACK#define REISERFS_IOC_UNPACK _IOW(0xCD,1,long)#endif#endif#ifdef LCF_LVMstruct lv_bmap { __u32 lv_block; __u16 lv_dev;};#ifndef LV_BMAP#define LV_BMAP _IOWR(0xfe, 0x30, 1)#endif#ifndef LVM_GET_IOP_VERSION#define LVM_GET_IOP_VERSION _IOR(0xfe, 0x98, 1)#endif#endif#ifdef LCF_EVMSstruct evms_get_bmap_t { __u64 rsector; __u32 dev; int status;};struct evms_version_t { __u32 major; __u32 minor; __u32 patch;};#ifndef EVMS_GET_BMAP#define EVMS_GET_BMAP _IOWR(MAJOR_EVMS, 0xC7, struct evms_get_bmap_t)#endif#ifndef EVMS_GET_IOCTL_VERSION#define EVMS_GET_IOCTL_VERSION _IOR(MAJOR_EVMS, 0x0, struct evms_version_t)#endif#endif#ifndef HDIO_GETGEO#define HDIO_GETGEO HDIO_REQ#endiftypedef struct _st_buf { struct _st_buf *next; struct stat st;} ST_BUF;DT_ENTRY *disktab = NULL;int old_disktab = 0;void geo_init(char *name){ FILE *file; char line[MAX_LINE+1]; char *here; DT_ENTRY *entry; int disk_section,items; if (name) { if ((file = fopen(name,"r")) == NULL) die("open %s: %s",name,strerror(errno)); } else if ((file = fopen(DFL_DISKTAB,"r")) == NULL) return; disk_section = !!disktab; while (fgets(line,MAX_LINE,file)) { here = strchr(line,'\n'); if (here) *here = 0; here = strchr(line,'#'); if (here) *here = 0; if (strspn(line," \t") != strlen(line)) { entry = alloc_t(DT_ENTRY); items = sscanf(line,"0x%x 0x%x %d %d %d %d",&entry->device, &entry->bios,&entry->sectors,&entry->heads,&entry->cylinders, &entry->start); if (items == 5) entry->start = -1; if (items < 5) die("Invalid line in %s:\n\"%s\"",name ? name : DFL_DISKTAB, line); entry->next = disktab; disktab = entry; if (disk_section) die("DISKTAB and DISK are mutually exclusive"); old_disktab = 1; } } (void) fclose(file);}void do_partition(void){ DT_ENTRY *entry,*walk; struct stat st; char *partition,*start; entry = alloc_t(DT_ENTRY); *entry = *disktab; entry->start = -1; partition = cfg_get_strg(cf_partitions,"partition"); if (stat(partition,&st) < 0) die("stat %s: %s",partition,strerror(errno)); if (!S_ISBLK(st.st_mode) || ((st.st_rdev ^ disktab->device) & D_MASK(st.st_rdev))) die("%s is not a valid partition device",partition); entry->device = st.st_rdev; cfg_init(cf_partition); (void) cfg_parse(cf_partition); start = cfg_get_strg(cf_partition,"start"); entry->start = start ? to_number(start) : -1; for (walk = disktab; walk; walk = walk->next) if (entry->device == walk->device) die("Duplicate geometry definition for %s",partition); entry->next = disktab; disktab = entry; cfg_init(cf_partitions);}int has_partitions(dev_t dev){ int major = MAJOR(dev); if ( major == MAJOR_HD || major == MAJOR_IDE2 || major == MAJOR_IDE3 || major == MAJOR_IDE4 || major == MAJOR_IDE5 || major == MAJOR_IDE6 || (major >= MAJOR_IDE7 && major <= MAJOR_IDE10) || major == MAJOR_XT || major == MAJOR_ESDI ) return 0xFFC0; if ( major == MAJOR_SD || (major >= MAJOR_SD2 && major <= MAJOR_SD8) || major == MAJOR_AMI_HYP || major == MAJOR_HPT370 || major == MAJOR_FL || major == MAJOR_NFTL || (major >= MAJOR_I2O && major <= MAJOR_I2O+7) || (major >= MAJOR_SMART2 && major <= MAJOR_SMART2+7) || (major >= MAJOR_CISS && major <= MAJOR_CISS+7) ) return 0xFFF0; /* 4 bit partition mask */ if ( major == MAJOR_IBM_iSER || (major >= MAJOR_DAC960 && major <= MAJOR_DAC960+7) ) return 0xFFF8; /* 3 bit partition mask */ return 0;}void do_disk(void){ DT_ENTRY *entry,*walk; struct stat st; char *disk,*bios,*sectors,*heads,*cylinders; entry = alloc_t(DT_ENTRY); disk = cfg_get_strg(cf_options,"disk"); if (stat(disk,&st) < 0) die("stat %s: %s",disk,strerror(errno)); if (!S_ISBLK(st.st_mode) || ((MINOR(st.st_rdev) & P_MASK(st.st_rdev)) && has_partitions(st.st_rdev))) die("RSN: %s is not a whole disk device",disk); entry->device = st.st_rdev; cfg_init(cf_disk); (void) cfg_parse(cf_disk); bios = cfg_get_strg(cf_disk,"bios"); sectors = cfg_get_strg(cf_disk,"sectors"); heads = cfg_get_strg(cf_disk,"heads"); cylinders = cfg_get_strg(cf_disk,"cylinders"); entry->bios = bios ? to_number(bios) : -1; if (!sectors && !heads) entry->sectors = entry->heads = -1; else if (!(sectors && heads)) die("Must specify SECTORS and HEADS together"); else { entry->sectors = to_number(sectors); entry->heads = to_number(heads); } if (cfg_get_flag(cf_disk,"inaccessible")) { entry->heads = 0; if (#if 0 cfg_get_strg(cf_disk,"bios") || #endif cfg_get_strg(cf_disk,"sectors") || cfg_get_strg(cf_disk,"heads") || cfg_get_strg(cf_disk,"cylinders")) die("No geometry variables allowed if INACCESSIBLE"); } entry->cylinders = cylinders ? to_number(cylinders) : -1; entry->start = 0; for (walk = disktab; walk; walk = walk->next) if (entry->device == walk->device) die("Duplicate geometry definition for %s",disk); entry->next = disktab; disktab = entry; cfg_init(cf_partitions); (void) cfg_parse(cf_partitions); cfg_unset(cf_options,"disk");}static int exists(const char *name){ struct hd_geometry dummy; int fd,yes; char buff; if ((fd = open(name,O_RDWR)) < 0) return 0; /* was O_RDONLY */ yes = read(fd,&buff,1) == 1 && ioctl(fd,HDIO_GETGEO,&dummy) >= 0; (void) close(fd); return yes;}#if 0static int scan_last_dev(ST_BUF *next,char *parent,int major,int increment){ DIR *dp; struct dirent *dir; char name[PATH_MAX+1]; ST_BUF st,*walk; int max,this; st.next = next; max = 0; if ((dp = opendir(parent)) == NULL) die("opendir %s: %s",parent,strerror(errno)); while ((dir = readdir(dp))) { sprintf(name,"%s/%s",parent,dir->d_name); if (stat(name,&st.st) >= 0) { if (S_ISBLK(st.st.st_mode) && MAJOR(st.st.st_rdev) == major && (MINOR(st.st.st_rdev) & (increment-1)) == 0) { this = MINOR(st.st.st_rdev)/increment+1; if (this > max && exists(name)) max = this; } if (S_ISDIR(st.st.st_mode) && strcmp(dir->d_name,".") && strcmp(dir->d_name,"..")) { for (walk = next; walk; walk = walk->next) if (stat_equal(&walk->st,&st.st)) break; if (!walk) { this = scan_last_dev(&st,name,major,increment); if (this > max) max = this; } } } } (void) closedir(dp); return max;}#endifstatic int last_dev(int major,int increment){/* * In version 12 to 18, LILO only relied on scan_last_dev (or last_dev). This * obviously didn't work if entries in /dev were missing. Versions 18 and 19 * added the probe loop, which seems to be okay, but which may probe for * invalid minor numbers. The IDE driver objects to that. Since last_dev is * only used to count IDE drives anyway, we try now only the first two devices * and forget about scan_last_dev. */#if 0 DEVICE dev; int minor; for (minor = 0; dev_open(&dev,(major << 8) | minor,-1); minor += increment) if (exists(dev.name)) dev_close(&dev); else { dev_close(&dev); return minor/increment; } return scan_last_dev(NULL,DEV_DIR,major,increment);#else DEVICE dev; int devs; for (devs = 0; devs < 2 && dev_open(&dev,(major << 8) | (increment*devs), -1); devs++) if (exists(dev.name)) dev_close(&dev); else { dev_close(&dev); break; } return devs;#endif}#ifdef LCF_LVMvoid lvm_bmap(struct lv_bmap *lbm){ DEVICE dev; static int lvmfd = -1; static dev_t last_dev = 0; if (lbm->lv_dev != last_dev) { char lvm_char[] = "/dev/lvm"; unsigned short iop; if (lvmfd != -1) close(lvmfd); if ((lvmfd = open(lvm_char, lbm->lv_dev, O_RDONLY)) < 0) die("can't open LVM char device %s\n", lvm_char); if (ioctl(lvmfd, LVM_GET_IOP_VERSION, &iop) < 0) die("LVM_GET_IOP_VERSION failed on %s\n", lvm_char); if (iop < 10) die("LVM IOP %d not supported for booting\n", iop); close(lvmfd); lvmfd = dev_open(&dev, lbm->lv_dev, O_RDONLY); if (lvmfd < 0) die("can't open LVM block device %#x\n", lbm->lv_dev); last_dev = lbm->lv_dev; } if (ioctl(lvmfd, LV_BMAP, lbm) < 0) { perror(__FUNCTION__); pdie("LV_BMAP error or ioctl unsupported, can't have image in LVM.\n"); }}#endif#ifdef LCF_EVMSvoid evms_bmap(struct evms_get_bmap_t *ebm){ DEVICE dev; static int evms_fd = -1; static dev_t evms_last_dev = 0; if (ebm->dev != evms_last_dev) { char evms_blk[] = "/dev/evms/block_device"; struct evms_version_t evms_ver; // Open the EVMS device if (evms_fd != -1) close(evms_fd); evms_fd = open(evms_blk, O_RDONLY); if (evms_fd < 0) die("Can't open EVMS block device %s.\n", evms_blk); // Get EVMS ioctl version number. if (ioctl(evms_fd, EVMS_GET_IOCTL_VERSION, &evms_ver) < 0) die("EVMS_GET_IOCTL_VERSION failed on %s.\n", evms_blk); // Check that the ioctl version is >= 7.1.0 if (evms_ver.major < 7 || (evms_ver.major == 7 && evms_ver.minor < 1)) die("EVMS ioctl version %d.%d.%d does not support booting.\n", evms_ver.major, evms_ver.minor, evms_ver.patch); close(evms_fd); evms_fd = dev_open(&dev, ebm->dev, O_RDONLY); if (evms_fd < 0) die("Can't open EVMS block device %#x\n", ebm->dev); evms_last_dev = ebm->dev; } if (ioctl(evms_fd, EVMS_GET_BMAP, ebm) < 0) { perror(__FUNCTION__); pdie("EVMS_GET_BMAP error or ioctl unsupported. Can't have image on EVMS volume.\n"); }}#endifstatic void geo_query_dev(GEOMETRY *geo,int device,int all){ DEVICE dev; int fd,get_all; struct floppy_struct fdprm; struct hd_geometry hdprm; get_all = all || MAJOR(device) != MAJOR_FD; if (!MAJOR(device)) die("Trying to map files from unnamed device 0x%04x (NFS ?)",device); if (device == MAJMIN_RAM) die("Trying to map files from your RAM disk. " "Please check -r option or ROOT environment variable."); if (get_all) fd = dev_open(&dev,device,O_NOACCESS); else fd = -1; /* pacify GCC */ switch (MAJOR(device)) { case MAJOR_FD: geo->device = device & 3; if (!get_all) { geo->heads = geo->cylinders = geo->sectors = 1; geo->start = 0; break; } if (ioctl(fd,FDGETPRM,&fdprm) < 0) die("geo_query_dev FDGETPRM (dev 0x%04x): %s",device, strerror(errno)); geo->heads = fdprm.head; geo->cylinders = fdprm.track; geo->sectors = fdprm.sect; geo->start = 0; break; case MAJOR_HD: /* fall through */ case MAJOR_IDE2: /* fall through */ case MAJOR_IDE3: /* fall through */ case MAJOR_IDE4: /* fall through */ case MAJOR_IDE5: /* fall through */ case MAJOR_IDE6: case MAJOR_IDE7: case MAJOR_IDE8: case MAJOR_IDE9: case MAJOR_IDE10: /* fall through */ case MAJOR_ESDI: /* fall through */ case MAJOR_XT: /* fall through */ if (ioctl(fd,HDIO_GETGEO,&hdprm) < 0) die("geo_query_dev HDIO_GETGEO (dev 0x%04x): %s",device, strerror(errno)); geo->heads = hdprm.heads; geo->cylinders = hdprm.cylinders; geo->sectors = hdprm.sectors; geo->start = hdprm.start; if ((geo->device = bios_device(geo, device)) < 0) geo->device = 0x80 + (MINOR(device) >> 6) + (MAJOR(device) == MAJOR_HD ? 0 : last_dev(MAJOR_HD,64)); break; case MAJOR_SD: case MAJOR_SD2: case MAJOR_SD3: case MAJOR_SD4: case MAJOR_SD5: case MAJOR_SD6: case MAJOR_SD7: case MAJOR_SD8: if (ioctl(fd,HDIO_GETGEO,&hdprm) < 0) die("geo_query_dev HDIO_GETGEO (dev 0x%04x): %s",device, strerror(errno)); if (all && !hdprm.sectors) die("HDIO_REQ not supported for your SCSI controller. Please " "use a DISK section"); geo->heads = hdprm.heads; geo->cylinders = hdprm.cylinders; geo->sectors = hdprm.sectors; geo->start = hdprm.start; if ((geo->device = bios_device(geo, device)) < 0) geo->device = 0x80 + last_dev(MAJOR_HD,64) + (MINOR(device) >> 4); break; case MAJOR_DAC960: case MAJOR_DAC960+1: case MAJOR_DAC960+2: case MAJOR_DAC960+3: case MAJOR_DAC960+4: case MAJOR_DAC960+5: case MAJOR_DAC960+6: case MAJOR_DAC960+7: case MAJOR_IBM_iSER: if (ioctl(fd,HDIO_GETGEO,&hdprm) < 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -