geometry.c

来自「LINUX lilo-22.7.1 源代码。」· C语言 代码 · 共 1,339 行 · 第 1/3 页

C
1,339
字号
#if BETA_TEST	if (verbose>=5) printf("geo_get(2):  device=%04X, all=%d\n", device, all);#endif/* if using hard disk, scan the devices in /proc/partitions */    if (has_partitions(device) && all)   pf_hard_disk_scan();    for (walk = disktab; walk; walk = walk->next)	if (walk->device == device) break;    inherited = !walk && !old_disktab;#if BETA_TEST    if (verbose>=5) printf("inherited=%d\n", inherited);#endif    if (inherited)	for (walk = disktab; walk; walk = walk->next)	    if (walk->device == (device & D_MASK(device))) break;#if BETA_TEST    if (verbose>=5) printf("walk=%08lx\n", (long)walk);#endif#if 1/* add 'all' to conditional below -- JRC 2002-08-20 */    if (walk && !walk->heads && all)#else/* Werner's original conditional */    if (walk && !walk->heads)#endif	die("Device 0x%04X: Configured as inaccessible.\n",device);    keep_cyls = !walk || walk->bios == -1 || walk->heads == -1 ||      walk->sectors == -1 || inherited || walk->start == -1;#if BETA_TEST    if (verbose>=5) printf("inherited=%d  keep_cyls=%d\n", inherited, keep_cyls);#endif#if 1/* add 'all' to conditional below -- JRC 2002-08-20 */    if (keep_cyls && (all || MAJOR(device)==MAJOR_FD) ) {#else/* Werner's original conditional */    if (keep_cyls) {#endif	geo_query_dev(geo,device,all);		if (all) bios_device(geo, device);		if (!nowarn && (geo->device & 0x7f) >= bios_max_devs() &&	  user_device == -1 && (!walk || walk->bios == -1))	    fprintf(errstd,"Warning: BIOS drive 0x%02x may not be accessible\n",	      geo->device);    }    if (walk) {	if (walk->bios != -1) geo->device = walk->bios;	if (walk->heads != -1) geo->heads = walk->heads;	if (walk->cylinders != -1 || !keep_cyls)	    geo->cylinders = walk->cylinders;	if (walk->sectors != -1) geo->sectors = walk->sectors;	if (walk->start != -1 && !inherited) geo->start = walk->start;    }    if (user_device != -1) geo->device = user_device;    if (!all) {	if (verbose > 2)	    printf("Device 0x%04x: BIOS drive 0x%02x, no geometry.\n",device,	      geo->device);	return;    }    if (!geo->heads || !geo->cylinders || !geo->sectors)	die("Device 0x%04X: Got bad geometry %d/%d/%d\n",device,	  geo->sectors,geo->heads,geo->cylinders);    if (geo->heads > BIOS_MAX_HEADS)	die("Device 0x%04X: Maximum number of heads is %d, not %d\n",device,	  BIOS_MAX_HEADS,geo->heads);    if (geo->heads == BIOS_MAX_HEADS && !nowarn)	fprintf(errstd, "Warning: Maximum number of heads = %d (as specified)\n"			"   exceeds standard BIOS maximum of 255.\n", geo->heads);    if (geo->sectors > BIOS_MAX_SECS)	die("Device 0x%04X: Maximum number of sectors is %d, not %d\n",	  device,BIOS_MAX_SECS,geo->sectors);    if (!lba32 &&      (geo->start+geo->sectors-1)/geo->heads/geo->sectors >= BIOS_MAX_CYLS &&      !nowarn) {	fprintf(errstd,"Warning: device 0x%04x exceeds %d cylinder limit.\n"        "   Use of the 'lba32' option may help on newer (EDD BIOS) systems.\n",	  device,BIOS_MAX_CYLS);    }    if (verbose >= 3) {	printf("Device 0x%04x: BIOS drive 0x%02x, %d heads, %d cylinders,\n",	  device,geo->device,geo->heads,geo->cylinders == -1 ? BIOS_MAX_CYLS :	  geo->cylinders);	printf("%15s%d sectors. Partition offset: %d sectors.\n","",	  geo->sectors,geo->start);    }    geo->raid = is_raid;/* make the serial number association */    if (!is_raid) register_bios(geo->device, device);    else geo->device = md_bios;		/* 22.5.7 add this else */        return;} /* end of geo_get */int geo_open(GEOMETRY *geo,char *name,int flags){    char *here;    int user_dev,block_size;    struct stat st;    if ((here = strrchr(name,':')) == NULL) user_dev = -1;    else {	fprintf(errstd,":BIOS syntax is no longer supported. Please use a "	  "DISK section\n");	*here++ = 0;	user_dev = to_number(here);    }    if ((geo->fd = open(name,flags)) < 0)	die("open %s: %s",name,strerror(errno));    if (fstat(geo->fd,&st) < 0) die("fstat %s: %s",name,strerror(errno));    if (!S_ISREG(st.st_mode) && !S_ISBLK(st.st_mode))	die("%s: neither a reg. file nor a block dev.",name);    geo->dev = S_ISREG(st.st_mode) ? st.st_dev : st.st_rdev;#if BETA_TEST	if (verbose>=4) {		printf("geo_open: (%s) st_dev(file)=%04X  st_rdev(blk)=%04X\n",		name,		(int)st.st_dev,		(int)st.st_rdev );	}#endif    geo_get(geo, geo->dev, user_dev, 1);    geo->file = S_ISREG(st.st_mode) ? st.st_dev : 0;    geo->boot = 0;#ifndef FIGETBSZ    geo->spb = 2;#else    if (!geo->file) geo->spb = 2;    else {	if (ioctl(geo->fd,FIGETBSZ,&block_size) < 0) {	    fprintf(errstd,"FIGETBSZ %s: %s\n",name,strerror(errno));	    geo->spb = 2;	}	else {	    if (!block_size || (block_size & (SECTOR_SIZE-1)))		die("Incompatible block size: %d\n",block_size);	    geo->spb = block_size/SECTOR_SIZE;	}    }#endif    return geo->fd;}int geo_open_boot(GEOMETRY *geo,char *name){    struct stat st;    if (verbose>=5) printf("geo_open_boot: %s\n", name);    if (stat(name,&st) < 0) die("stat %s: %s",name,strerror(errno));    if (!S_ISREG(st.st_mode) && !S_ISBLK(st.st_mode))	die("%s: neither a reg. file nor a block dev.",name);    geo->dev = S_ISREG(st.st_mode) ? st.st_dev : st.st_rdev;#if 1    if (MAJOR(geo->dev) == MAJOR_FD) geo->fd = 0;    else if ((geo->fd = open(name,O_NOACCESS)) < 0)	    die("open %s: %s",name,strerror(errno));#else    if (MAJOR(geo->dev) != MAJOR_FD) {	if ((P_MASK(geo->dev) & geo->dev) != 0)	    die("UNSAFE may be used with floppy or MBR only");    }    geo->fd = 0;#endif    geo_get(geo, geo->dev, -1, 0);    geo->file = S_ISREG(st.st_mode);    geo->raid = 0;    geo->boot = 1;    geo->spb = 1;    return geo->fd;}void geo_close(GEOMETRY *geo){    if (geo->fd) (void) close(geo->fd);    geo->fd = 0;}#ifndef FIBMAP#define FIBMAP BMAP_IOCTL#endifint geo_comp_addr(GEOMETRY *geo,int offset,SECTOR_ADDR *addr){    int block,sector;    static int warnings = 0;#if BETA_TEST    if (verbose>=6)	printf("geo_comp_addr: dev = %x, offset=%d\n",		geo->device, offset);#endif#if 0    if (linear && lba32)       die("'linear' and 'lba32' (-l and -L) are mutually exclusive.");#endif    if (geo->boot && offset >= SECTOR_SIZE)	die("Internal error: sector > 0 after geo_open_boot");    block = offset/geo->spb/SECTOR_SIZE;    if (geo->file) {#ifdef LCF_REISERFS	    struct statfs buf;	    fstatfs(geo->fd, &buf);	    if (buf.f_type == REISERFS_SUPER_MAGIC) {		if (ioctl (geo->fd, REISERFS_IOC_UNPACK, 1) == ENOSPC)			die("Cannot unpack ReiserFS file");		if (verbose > 3) printf("fd %d: REISERFS_IOC_UNPACK\n", geo->fd);	    }        /* Forcing reiser4 to perform tail2extent converstion */           if (buf.f_type == REISER4_SUPER_MAGIC) {               if (ioctl (geo->fd, REISER4_IOC_UNPACK, 1) != 0)                       die("Cannot unpack Reiser4 file");               if (verbose > 3) printf("fd %d: REISER4_IOC_UNPACK\n", geo->fd);           /*                As we may have the situation when extent will be included               into transaction, and its item(s) will not be have the real block               numbers assigned, we should perform fsync() in order to guarantee,               that current atom is flushed and real block numbers assigned to                the extent(s) file was converted in.           */		if (fdatasync(geo->fd) != 0)		    die("Cannot perform fdatasync");           		if (verbose > 3) printf("fd %d: fdatasync()\n", geo->fd);           }#endif	if (ioctl(geo->fd,FIBMAP,&block) < 0) pdie("ioctl FIBMAP");	if (!block) {	    return 0;	}    }#ifdef LCF_LVM    if (MAJOR(geo->dev) == MAJOR_LVM) {	struct lv_bmap lbm;	lbm.lv_dev = geo->dev;	lbm.lv_block = block;	lvm_bmap(&lbm);	if (lbm.lv_dev != geo->base_dev)	    die("LVM boot LV cannot be on multiple PVs\n");	block = lbm.lv_block;    }#endif#ifdef LCF_EVMS    if (MAJOR(geo->dev) == MAJOR_EVMS) {        struct evms_get_bmap_t ebm;                                  ebm.rsector = block * geo->spb;        ebm.dev = geo->dev;        ebm.status = 0;                                    evms_bmap(&ebm);        if (ebm.dev != geo->base_dev)            die("EVMS boot volume cannot be on multiple disks.\n");        sector = ebm.rsector + ((offset/SECTOR_SIZE) % geo->spb) + geo->start;    }    else {        sector = block*geo->spb+((offset/SECTOR_SIZE) % geo->spb);        sector += geo->start;    }#else    sector = block*geo->spb+((offset/SECTOR_SIZE) % geo->spb);    sector += geo->start;#endif /*   DON'T always use CHS addressing on floppies:     JRC   *//*    if ((geo->device & 0x80) && (linear || lba32)) {	*/    if ((linear || lba32)) {        addr->device = geo->device | (linear ? LINEAR_FLAG : (LBA32_FLAG|LBA32_NOCOUNT))#if 0       		| (do_md_install && geo->file==boot_dev_nr ? RAID_REL_FLAG : 0);#else       		| (do_md_install && geo->raid ? RAID_REL_FLAG : 0);#endif        addr->num_sect = linear ? 1 : (sector >> 24);	addr->sector = sector & 0xff;	addr->track = (sector >> 8) & 0xff;	addr->head = sector >> 16;	if (linear) {	    int cyl = sector;	    if (geo->sectors>0 && geo->heads>0) {	    	cyl /= geo->sectors;	    	cyl /= geo->heads;	    	if (cyl >= BIOS_MAX_CYLS && !nowarn && warnings++ < 8) {		    fprintf(errstd,			"Warning:  LINEAR may generate cylinder# above 1023 at boot-time.\n");	    	}	    }            if (sector/(63*255) >= BIOS_MAX_CYLS)		die("Sector address %d too large for LINEAR"					" (try LBA32 instead).", sector);	}	if (verbose > 4)	    printf("fd %d: offset %d -> dev 0x%02x, %s %d\n",		         geo->fd, offset, addr->device,		         lba32 ? "LBA" : "linear",		         sector);    }    else {	addr->device = geo->device;	addr->sector = 1;	addr->head = 0;	if (sector) {	    if (geo->heads == 0)		die("BIOS device 0x%02x is inaccessible", geo->device);	    addr->sector = (sector % geo->sectors)+1; 	    sector /= geo->sectors;	    addr->head = sector % geo->heads;	    sector /= geo->heads;	}	if (sector >= BIOS_MAX_CYLS)	    die("geo_comp_addr: Cylinder number is too big (%d > %d)",sector,	      BIOS_MAX_CYLS-1);	if (sector >= geo->cylinders && geo->cylinders != -1)	    die("geo_comp_addr: Cylinder %d beyond end of media (%d)",sector,	      geo->cylinders);	if (verbose > 4)	    printf("fd %d: offset %d -> dev 0x%02x, head %d, track %d, sector %d\n",	      geo->fd,offset,addr->device,addr->head,sector,addr->sector);	addr->track = sector & 255;	addr->sector |= (sector >> 8) << 6;        addr->num_sect = 1;    }    return 1;}int geo_find(GEOMETRY *geo,SECTOR_ADDR addr){    SECTOR_ADDR here;    struct stat st;    int i;#if DEBUG_NEW    if (verbose>=2) {	printf("Find:  AL=%02x  CX=%04x  DX=%04x  LBA=%d\n", (int)addr.num_sect,		addr.sector + (addr.track<<8),		addr.device + (addr.head<<8),		addr.sector + (addr.track<<8) + (addr.head<<16) +		(addr.device&(LBA32_FLAG|LBA32_NOCOUNT)?addr.num_sect<<24:0) );    }#endif    if (fstat(geo->fd,&st) < 0) return 0;    geo_get(geo,st.st_dev,-1,1);    for (i = 0; i < (st.st_size+SECTOR_SIZE-1)/SECTOR_SIZE; i++)	if (geo_comp_addr(geo,i*SECTOR_SIZE,&here))	    if (here.sector == addr.sector && here.track == addr.track &&	      here.device == addr.device && here.head == addr.head &&	      here.num_sect == addr.num_sect ) {		if (lseek(geo->fd,i*SECTOR_SIZE,SEEK_SET) < 0) return 0;		else return 1;	    }    return 1;}#if 0int geo_devscan(int device){    DT_ENTRY *walk;    unsigned int mask, codes = 0;    int bios;    int maxbios = 0;        device &= D_MASK(device);/* mark those BIOS codes that are already used */    for (walk=disktab; walk; walk=walk->next) {	if (has_partitions(walk->device) && walk->bios != -1) {	    bios = walk->bios & 0x7F;	    if (bios >= 4*sizeof(codes) ) die("BIOS code %02X is too big (device %04X)", bios, device);	    codes |= 1 << bios;		}    }    bios = -1;/* extract BIOS code of master device, or -1 */    for (walk=disktab; walk; walk=walk->next) {	if (device == walk->device) {	    bios = walk->bios;	}    }    if (bios > maxbios) maxbios = bios;/* if device has no BIOS code assigned, assign the next one */    if (bios == -1)	for (bios=0x80, mask=1; mask; mask<<=1, bios++)		if (!(mask&codes)) break;        if (bios > DEV_MASK) die("geo_devscan:  ran out of device codes");        for (walk=disktab; walk; walk=walk->next) {	if (device == walk->device) {	    if (walk->bios == -1) walk->bios = bios;	    else bios = walk->bios;	    break;	}    }    if (bios > maxbios) maxbios = bios;        if (verbose >= 2) printf("geo_devscan:  maxbios = %02X\n", maxbios);        if (walk) return maxbios;	/* there was an entry in the disktab */        walk = alloc_t(DT_ENTRY);    walk->device = device;    walk->bios = bios;    walk->sectors = walk->heads = walk->cylinders = walk->start = -1;    walk->next = disktab;    disktab = walk;    if (verbose>=2)	printf("geo_devscan: arbitrary bios assignment  dev=%04X  bios=0x%02X\n",			device, bios);    for (walk=disktab; walk; walk=walk->next) {	if (device == (walk->device & D_MASK(walk->device))) {	    if (walk->bios != -1) walk->bios = bios;	}    }    return maxbios;}#endif

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?