📄 partition.c
字号:
/* partition.c - Partition table handling *//*Copyright 1992-1998 Werner Almesberger.Copyright 1999-2004 John Coffman.All rights reserved.Licensed under the terms contained in the file 'COPYING' in the source directory.*/#define _GNU_SOURCE#include <stdlib.h>#include <stdio.h>#include <string.h>#include <ctype.h>#include <fcntl.h>#include <errno.h>#include <sys/stat.h>#include <sys/types.h>#include <limits.h>#include <time.h>#include <dirent.h>#include "config.h"#include "lilo.h"#include "common.h"#include "cfg.h"#include "device.h"#include "geometry.h"#include "partition.h"#include "boot.h"#include "loader.h"#if __GLIBC__ < 2 || __GLIBC_MINOR__ < 1#if defined(_syscall5) && defined(__NR__llseek) _syscall5(int, _llseek, unsigned int, fd, unsigned int, hi, unsigned int, lo, lloff_t *, res, unsigned int, wh); int _llseek(unsigned int fd, unsigned int offset_high, unsigned int offset_low, lloff_t * result, unsigned int whence); lloff_t lseek64(unsigned int fd, lloff_t offs, unsigned int whence) { lloff_t res; return _llseek(fd, offs>>32, offs, &res, whence) < 0 ? (lloff_t)(-1) : res; }#else/* last ditch attempt on small disks, and very old systems */# warning "*****************************************"# warning "***** no 64 bit lseek is available ******"# warning "***** using 23 bit sector addresses *****"# warning "*****************************************"# define lseek64 lseek#endif#endifstaticint anywhere(void *buf, unsigned char *str){ int k, n; void *s; k = strlen(str); n = SECTOR_SIZE-k; s = memchr(buf, *str, n); while(s) { if (!strncmp(s, str, k)) return 1; s++; n = SECTOR_SIZE - k - (int)(s-buf); s = memchr(s, *str, n); } return 0;}/* identify partitions which would be destroyed if the boot block is overwritten: known problems occur for: XFS NTFS DOS FAT (relocation will fix)*/int part_nowrite(char* device){ int fd; BOOT_SECTOR bs; int ret=PTW_OKAY; /* say ok, unless we recognize a problem partition */if ( !(do_md_install && extra==X_MBR_ONLY) ) { if ((fd = open(device, O_RDONLY)) < 0) pdie("part_nowrite check:"); if (read(fd, bs.sector, sizeof(bs)) != SECTOR_SIZE) pdie("part_nowrite: read:"); /* check for XFS */ if (!strncmp("XFSB", bs.sector, 4)) ret=PTW_XFS; /* check for NTFS */ else if ( !strncmp("NTFS", bs.par_d.system, 4) || anywhere(bs.sector,"NTLDR") ) ret=PTW_NTFS;/* check for HPFS */ else if ( !strncmp("OS2", bs.par_d.system, 3) || anywhere(bs.sector,"OS2LDR") ) ret=PTW_OS2;/* check for DOS FAT */ else if ( (bs.par_d.bpb.media_descriptor >= 0xF8 || bs.par_d.bpb.media_descriptor == 0xF0) && *(short*)bs.par_d.bpb.bytes_per_sector == SECTOR_SIZE && (bs.par_d.bpb.number_of_FATs==1 || bs.par_d.bpb.number_of_FATs==2) /* sectors_per_cluster is a power of 2, meaning only 1 bit is on */ && bs.par_d.bpb.sectors_per_cluster && (bs.par_d.bpb.sectors_per_cluster & (bs.par_d.bpb.sectors_per_cluster-1))==0 ) { ret=PTW_DOS;#if 0/* this, it turns out is from Windows 98, so no caution here on NT */ if (anywhere(bs.sector,"WINBOOT SYS")) ret+=PTW_NTFS;#endif } /* check for SWAP -- last check, as 'bs' is overwritten */ else if (*(int*)bs.sector == 0xFFFFFFFEU) { if (lseek(fd, (PAGE_SIZE)-SECTOR_SIZE, SEEK_SET) != (PAGE_SIZE)-SECTOR_SIZE) pdie("part_nowrite lseek:"); if (SECTOR_SIZE != read(fd, bs.sector, sizeof(bs)) ) pdie("part_nowrite swap check:"); if (!strncmp(bs.sector+SECTOR_SIZE-10,"SWAPSPACE2",10) || !strncmp(bs.sector+SECTOR_SIZE-10,"SWAP-SPACE",10) ) ret=PTW_SWAP; }/* didn't recognize the superblock type, so assume it is okay */ else ret=PTW_OKAY; close(fd);} /* raid install with X_MBR_ONLY in use */ if (verbose>=6) printf("part_nowrite: %d\n", ret); return ret;}void part_verify(int dev_nr,int type){ GEOMETRY geo; DEVICE dev; char backup_file[PATH_MAX+1]; int fd, bck_file, part, size, lin_3d, cyl; unsigned int second, base; struct partition part_table[PART_MAX]; int mask, i, pe, Linux, dos, mbr; unsigned short boot_sig; BOOT_PARAMS_1 bs; if (!has_partitions(dev_nr) || !(mask = P_MASK(dev_nr)) || !(dev_nr & mask)#if 0 || (dev_nr & mask) > PART_MAX#endif ) return; if (verbose >= 4) printf("part_verify: dev_nr=%04x, type=%d\n", dev_nr, type); geo_get(&geo,dev_nr & ~mask,-1,1); fd = dev_open(&dev,dev_nr & ~mask,cfg_get_flag(cf_options,"fix-table") && !test ? O_RDWR : O_RDONLY); part = (pe = dev_nr & mask)-1;#if 1 if (type) { if (lseek(fd, 0L, SEEK_SET) != 0 || read(fd, &bs, sizeof(bs)) != sizeof(bs) ) pdie("bs read"); if (*(int*)bs.signature==EX_MAG_HL) mbr = bs.stage; else mbr = STAGE_MBR; } else mbr = STAGE_MBR;#endif if (lseek(fd, PART_TABLE_OFFSET, SEEK_SET) < 0) pdie("lseek partition table"); if (!(size = read(fd,(char *) part_table, sizeof(struct partition)* PART_MAX))) die("Short read on partition table"); if (size < 0) pdie("read partition table"); if ( read(fd, &boot_sig, sizeof(boot_sig)) != sizeof(boot_sig) || boot_sig != BOOT_SIGNATURE ) die("read boot signature failed"); if (verbose>=5) printf("part_verify: part#=%d\n", pe); second=base=0; for (i=0; i<PART_MAX; i++) { if (is_extd_part(part_table[i].sys_ind)) { if (!base) base = part_table[i].start_sect; else die("invalid partition table: second extended partition found"); } } i=5; while (i<=pe && base) { if (lseek64(fd, LLSECTORSIZE*(base+second) + PART_TABLE_OFFSET, SEEK_SET) < 0) die("secondary lseek64 failed"); if (read(fd, part_table, sizeof(part_table)) != sizeof(part_table)) die("secondary read pt failed"); if ( read(fd, &boot_sig, sizeof(boot_sig)) != sizeof(boot_sig) || boot_sig != BOOT_SIGNATURE ) die("read second boot signature failed"); if (is_extd_part(part_table[1].sys_ind)) second=part_table[1].start_sect; else base = 0; i++; part=0; }#if 1 if (type && pe>0 && pe<=(mbr==STAGE_MBR2?63:PART_MAX) && !(part_table[part].boot_ind&0x80) && !nowarn) fprintf(errstd,"Warning: Partition %d on %s is not marked Active.\n", pe, dev.name);#endif i = part_table[part].sys_ind; Linux = i == PART_LINUX_MINIX || i == PART_LINUX_NATIVE || is_extd_part(i); i &= ~HIDDEN_OFF; dos = i == PART_DOS12 || i == PART_DOS16_SMALL || i == PART_DOS16_BIG || i == PART_FAT32 || i == PART_FAT32_LBA || i == PART_FAT16_LBA ; if (type && !Linux) { fflush(stdout); if (!nowarn) fprintf(errstd,"Warning: partition type 0x%02X"" on device 0x%04X is a dangerous place for\n" " a boot sector.", part_table[part].sys_ind, dev_nr); if (dos && !nowarn) fprintf(errstd," A DOS/Windows/OS2 system may be rendered unbootable." "\n The backup copy of this boot sector should be retained."); if (!nowarn) fprintf(errstd,"\n");#if 0 if (!dos && !cfg_get_flag(cf_options,"ignore-table")) die("You may proceed by using either '-P ignore' or 'ignore-table'");#else if (!yesno("\nProceed? ", 0)) exit(0);#endif } cyl = part_table[part].cyl+((part_table[part].sector >> 6) << 8); lin_3d = (part_table[part].sector & 63)-1+(part_table[part].head+ cyl*geo.heads)*geo.sectors; if (pe <= PART_MAX && (lin_3d > part_table[part].start_sect || (lin_3d < part_table[part].start_sect && cyl != BIOS_MAX_CYLS-1)) && !nowarn) { fflush(stdout); fprintf(errstd,"Device 0x%04X: Inconsistent partition table, %d%s entry\n", dev_nr & ~mask,part+1,!part ? "st" : part == 1 ? "nd" : part == 2 ? "rd" : "th"); fprintf(errstd," CHS address in PT: %d:%d:%d --> LBA (%d)\n", cyl, part_table[part].head, part_table[part].sector & 63, lin_3d); cyl = part_table[part].start_sect/geo.sectors/geo.heads; fprintf(errstd," LBA address in PT: %d --> CHS (%d:%d:%d)\n", part_table[part].start_sect, cyl, part_table[part].head = (part_table[part].start_sect/geo.sectors) % geo.heads, part_table[part].sector = (part_table[part].start_sect % geo.sectors)+1 ); if (cyl >= BIOS_MAX_CYLS) cyl = BIOS_MAX_CYLS-1; part_table[part].sector |= (cyl >> 8)<<6; part_table[part].cyl = cyl & 0xff; if (!cfg_get_flag(cf_options,"fix-table") && !cfg_get_flag(cf_options, "ignore-table")) die("Either FIX-TABLE or IGNORE-TABLE must be specified\n" "If not sure, first try IGNORE-TABLE (-P ignore)"); if (test || cfg_get_flag(cf_options,"ignore-table")) fprintf(errstd,"The partition table is *NOT* being adjusted.\n"); else { sprintf(backup_file,BACKUP_DIR "/part.%04X",dev_nr & ~mask); if ((bck_file = creat(backup_file,0644)) < 0) die("creat %s: %s",backup_file,strerror(errno)); if (!(size = write(bck_file,(char *) part_table, sizeof(struct partition)*PART_MAX))) die("Short write on %s",backup_file); if (size < 0) pdie(backup_file); if (close(bck_file) < 0) die("close %s: %s",backup_file,strerror(errno)); if (verbose > 0) printf("Backup copy of partition table in %s\n",backup_file); printf("Writing modified partition table to device 0x%04X\n", dev_nr & ~mask); if (lseek(fd,PART_TABLE_OFFSET,SEEK_SET) < 0) pdie("lseek partition table"); if (!(size = write(fd,(char *) part_table,sizeof(struct partition)* PART_MAX))) die("Short write on partition table"); if (size < 0) pdie("write partition table"); } } dev_close(&dev);}CHANGE_RULE *change_rules = NULL;void do_cr_reset(void){ CHANGE_RULE *next; while (change_rules) { next = change_rules->next; free((char *) change_rules->type); free(change_rules); change_rules = next; }}static unsigned char cvt_byte(const char *s){ char *end; unsigned int value; value = strtoul(s,&end,0); if (value > 255 || *end) cfg_error("\"%s\" is not a byte value",s); return value;}static void add_type(const char *type,int normal,int hidden){ CHANGE_RULE *rule; for (rule = change_rules; rule; rule = rule->next) if (!strcasecmp(rule->type,type)) die("Duplicate type name: \"%s\"",type); rule = alloc_t(CHANGE_RULE); rule->type = stralloc(type); rule->normal = normal == -1 ? hidden ^ HIDDEN_OFF : normal; rule->hidden = hidden == -1 ? normal ^ HIDDEN_OFF : hidden; rule->next = change_rules; change_rules = rule;}void do_cr_type(void){ const char *normal,*hidden; cfg_init(cf_change_rule); (void) cfg_parse(cf_change_rule); normal = cfg_get_strg(cf_change_rule,"normal"); hidden = cfg_get_strg(cf_change_rule,"hidden"); if (normal) add_type(cfg_get_strg(cf_change_rules,"type"),cvt_byte(normal), hidden ? cvt_byte(hidden) : -1); else { if (!hidden) cfg_error("At least one of NORMAL and HIDDEN must be present"); add_type(cfg_get_strg(cf_change_rules,"type"),cvt_byte(hidden),-1); } cfg_unset(cf_change_rules,"type");}void do_cr(void){ cfg_init(cf_change_rules); (void) cfg_parse(cf_change_rules);}#if defined(LCF_REWRITE_TABLE) && !defined(LCF_READONLY)/* * Rule format: * * +------+------+------+------+ * |drive |offset|expect| set | * +------+------+------+------+ * 0 1 2 3 */static void add_rule(unsigned char bios,unsigned char offset, unsigned char expect,unsigned char set){ int i; if (curr_prt_map == PRTMAP_SIZE) cfg_error("Too many change rules (more than %s)",PRTMAP_SIZE); if (verbose >= 3) printf(" Adding rule: disk 0x%02x, offset 0x%x, 0x%02x -> 0x%02x\n", bios,PART_TABLE_OFFSET+offset,expect,set); prt_map[curr_prt_map] = (set << 24) | (expect << 16) | (offset << 8) | bios; for (i = 0; i < curr_prt_map; i++) { if (prt_map[i] == prt_map[curr_prt_map]) die("Repeated rule: disk 0x%02x, offset 0x%x, 0x%02x -> 0x%02x", bios,PART_TABLE_OFFSET+offset,expect,set); if ((prt_map[i] & 0xffff) == ((offset << 8) | bios) && (prt_map[i] >> 24) == expect) die("Redundant rule: disk 0x%02x, offset 0x%x: 0x%02x -> 0x%02x " "-> 0x%02x",bios,PART_TABLE_OFFSET+offset, (prt_map[i] >> 16) & 0xff,expect,set); } curr_prt_map++;}#endifstatic int has_partition;static CHANGE_RULE *may_change(unsigned char sys_ind){ CHANGE_RULE *cr = change_rules; while (cr) { if (cr->normal == sys_ind || cr->hidden == sys_ind) return cr; cr = cr->next; } return NULL;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -