1 /* partition.c - Partition table handling */
3 Copyright 1992-1998 Werner Almesberger.
4 Copyright 1999-2005 John Coffman.
7 Licensed under the terms contained in the file 'COPYING' in the
20 #include <sys/types.h>
30 #include "partition.h"
34 #if __GLIBC__ < 2 || __GLIBC_MINOR__ < 1
35 #if defined(_syscall5) && defined(__NR__llseek)
37 _syscall5(int, _llseek, unsigned int, fd, unsigned int, hi,
38 unsigned int, lo, lloff_t *, res, unsigned int, wh);
39 int _llseek(unsigned int fd, unsigned int offset_high,
40 unsigned int offset_low, lloff_t * result, unsigned int whence);
42 lloff_t lseek64(unsigned int fd, lloff_t offs, unsigned int whence)
44 return _llseek(fd, offs>>32, offs, &res, whence) < 0 ?
49 /* last ditch attempt on small disks, and very old systems */
50 # warning "*****************************************"
51 # warning "***** no 64 bit lseek is available ******"
52 # warning "***** using 23 bit sector addresses *****"
53 # warning "*****************************************"
54 # define lseek64 lseek
59 int anywhere(unsigned char *buf, char *str)
66 s = memchr(buf, *str, n);
68 if (!strncmp(s, str, k)) return 1;
70 n = SECTOR_SIZE - k - (int)(s-(char*)buf);
71 s = memchr(s, *str, n);
78 /* identify partitions which would be destroyed if the boot block
81 known problems occur for:
84 DOS FAT (relocation will fix)
87 int part_nowrite(char* device)
92 int ret=PTW_OKAY; /* say ok, unless we recognize a problem partition */
93 if ( !(do_md_install && extra==X_MBR_ONLY) ) {
94 if ((fd = open(device, O_RDONLY)) < 0) pdie("part_nowrite check:");
95 if (read(fd, bs.sector, sizeof(bs)) != SECTOR_SIZE) pdie("part_nowrite: read:");
98 if (!strncmp("XFSB", (char*)bs.sector, 4)) ret=PTW_XFS;
101 else if ( !strncmp("NTFS", bs.par_d.system, 4)
102 || anywhere(bs.sector,"NTLDR") ) ret=PTW_NTFS;
105 else if ( !strncmp("OS2", bs.par_d.system, 3)
106 || anywhere(bs.sector,"OS2LDR") ) ret=PTW_OS2;
108 /* check for DOS FAT */
110 (bs.par_d.bpb.media_descriptor >= 0xF8 || bs.par_d.bpb.media_descriptor == 0xF0)
111 && *(short*)bs.par_d.bpb.bytes_per_sector == SECTOR_SIZE
112 && (bs.par_d.bpb.number_of_FATs==1 || bs.par_d.bpb.number_of_FATs==2)
113 /* sectors_per_cluster is a power of 2, meaning only 1 bit is on */
114 && bs.par_d.bpb.sectors_per_cluster
115 && (bs.par_d.bpb.sectors_per_cluster & (bs.par_d.bpb.sectors_per_cluster-1))==0
119 /* this, it turns out is from Windows 98, so no caution here on NT */
120 if (anywhere(bs.sector,"WINBOOT SYS")) ret+=PTW_NTFS;
124 /* check for SWAP -- last check, as 'bs' is overwritten */
125 else if (*(int*)bs.sector == 0xFFFFFFFEU) {
126 if (lseek(fd, (PAGE_SIZE)-SECTOR_SIZE, SEEK_SET) != (PAGE_SIZE)-SECTOR_SIZE)
127 pdie("part_nowrite lseek:");
128 if (SECTOR_SIZE != read(fd, bs.sector, sizeof(bs)) ) pdie("part_nowrite swap check:");
129 if (!strncmp((char*)bs.sector+SECTOR_SIZE-10,"SWAPSPACE2",10)
130 || !strncmp((char*)bs.sector+SECTOR_SIZE-10,"SWAP-SPACE",10) ) ret=PTW_SWAP;
133 /* didn't recognize the superblock type, so assume it is okay */
138 } /* raid install with X_MBR_ONLY in use */
139 if (verbose>=6) printf("part_nowrite: %d\n", ret);
145 void part_verify(int dev_nr,int type)
149 char backup_file[PATH_MAX+1];
150 int fd, bck_file, part, size, lin_3d, cyl;
151 unsigned int second, base;
152 struct partition part_table[PART_MAX];
153 int mask, i, pe, Linux, dos, mbr;
154 unsigned short boot_sig;
157 if (!has_partitions(dev_nr) || !(mask = P_MASK(dev_nr)) || !(dev_nr & mask)
159 || (dev_nr & mask) > PART_MAX
163 if (verbose >= 4) printf("part_verify: dev_nr=%04x, type=%d\n", dev_nr, type);
164 geo_get(&geo,dev_nr & ~mask,-1,1);
165 fd = dev_open(&dev,dev_nr & ~mask,cfg_get_flag(cf_options,"fix-table")
166 && !test ? O_RDWR : O_RDONLY);
167 part = (pe = dev_nr & mask)-1;
170 if (lseek(fd, 0L, SEEK_SET) != 0 ||
171 read(fd, &bs, sizeof(bs)) != sizeof(bs) ) pdie("bs read");
172 if (*(int*)bs.signature==EX_MAG_HL) mbr = bs.stage;
173 else mbr = STAGE_MBR;
174 } else mbr = STAGE_MBR;
176 if (lseek(fd, PART_TABLE_OFFSET, SEEK_SET) < 0) pdie("lseek partition table");
177 if (!(size = read(fd,(char *) part_table, sizeof(struct partition)*
178 PART_MAX))) die("Short read on partition table");
179 if (size < 0) pdie("read partition table");
180 if ( read(fd, &boot_sig, sizeof(boot_sig)) != sizeof(boot_sig) ||
181 boot_sig != BOOT_SIGNATURE ) die("read boot signature failed");
183 if (verbose>=5) printf("part_verify: part#=%d\n", pe);
186 for (i=0; i<PART_MAX; i++) {
187 if (is_extd_part(part_table[i].sys_ind)) {
188 if (!base) base = part_table[i].start_sect;
189 else die("invalid partition table: second extended partition found");
193 while (i<=pe && base) {
194 if (lseek64(fd, LLSECTORSIZE*(base+second) + PART_TABLE_OFFSET, SEEK_SET) < 0)
195 die("secondary lseek64 failed");
196 if (read(fd, part_table, sizeof(part_table)) != sizeof(part_table)) die("secondary read pt failed");
197 if ( read(fd, &boot_sig, sizeof(boot_sig)) != sizeof(boot_sig) ||
198 boot_sig != BOOT_SIGNATURE ) die("read second boot signature failed");
199 if (is_extd_part(part_table[1].sys_ind)) second=part_table[1].start_sect;
205 if (type && pe>0 && pe<=(mbr==STAGE_MBR2?63:PART_MAX)
206 && !(part_table[part].boot_ind&0x80) )
207 warn("Partition %d on %s is not marked Active.",
210 i = part_table[part].sys_ind;
212 Linux = i == PART_LINUX_MINIX ||
213 i == PART_LINUX_NATIVE ||
214 i == PART_LINUX_LVM ||
218 dos = i == PART_DOS12 ||
219 i == PART_DOS16_SMALL ||
220 i == PART_DOS16_BIG ||
222 i == PART_FAT32_LBA ||
223 i == PART_FAT16_LBA ||
225 i == PART_OS2_BOOTMGR ;
227 if (type && !Linux) {
228 warn("partition type 0x%02X"" on device 0x%04X is a dangerous place for\n"
230 part_table[part].sys_ind, dev_nr,
231 dos ? " A DOS/Windows/OS2 system may be rendered unbootable."
232 "\n The backup copy of this boot sector should be retained."
235 if (!dos && !cfg_get_flag(cf_options,"ignore-table"))
236 die("You may proceed by using either '-P ignore' or 'ignore-table'");
238 if (!yesno("\nProceed? ", 0)) exit(0);
241 cyl = part_table[part].cyl+((part_table[part].sector >> 6) << 8);
242 lin_3d = (part_table[part].sector & 63)-1+(part_table[part].head+
243 cyl*geo.heads)*geo.sectors;
244 if (pe <= PART_MAX &&
245 (lin_3d > part_table[part].start_sect || (lin_3d <
246 part_table[part].start_sect && cyl != BIOS_MAX_CYLS-1)) ) {
247 warn("Device 0x%04X: Inconsistent partition table, %d%s entry",
248 dev_nr & ~mask,part+1,!part ? "st" : part == 1 ? "nd" : part ==
251 fprintf(errstd," CHS address in PT: %d:%d:%d --> LBA (%d)\n",
253 part_table[part].head,
254 part_table[part].sector & 63,
256 cyl = part_table[part].start_sect/geo.sectors/geo.heads;
258 fprintf(errstd," LBA address in PT: %d --> CHS (%d:%d:%d)\n",
259 part_table[part].start_sect,
261 part_table[part].head = (part_table[part].start_sect/geo.sectors) % geo.heads,
262 part_table[part].sector = (part_table[part].start_sect % geo.sectors)+1
264 if (cyl >= BIOS_MAX_CYLS) cyl = BIOS_MAX_CYLS-1;
265 part_table[part].sector |= (cyl >> 8)<<6;
266 part_table[part].cyl = cyl & 0xff;
267 if (!cfg_get_flag(cf_options,"fix-table") && !cfg_get_flag(cf_options,
268 "ignore-table")) die("Either FIX-TABLE or IGNORE-TABLE must be specified\n"
269 "If not sure, first try IGNORE-TABLE (-P ignore)");
270 if (test || cfg_get_flag(cf_options,"ignore-table")) {
271 warn("The partition table is *NOT* being adjusted.");
273 sprintf(backup_file,BACKUP_DIR "/part.%04X",dev_nr & ~mask);
274 if ((bck_file = creat(backup_file,0644)) < 0)
275 die("creat %s: %s",backup_file,strerror(errno));
276 if (!(size = write(bck_file,(char *) part_table,
277 sizeof(struct partition)*PART_MAX)))
278 die("Short write on %s",backup_file);
279 if (size < 0) pdie(backup_file);
280 if (close(bck_file) < 0)
281 die("close %s: %s",backup_file,strerror(errno));
283 printf("Backup copy of partition table in %s\n",backup_file);
284 printf("Writing modified partition table to device 0x%04X\n",
286 if (lseek(fd,PART_TABLE_OFFSET,SEEK_SET) < 0)
287 pdie("lseek partition table");
288 if (!(size = write(fd,(char *) part_table,sizeof(struct partition)*
289 PART_MAX))) die("Short write on partition table");
290 if (size < 0) pdie("write partition table");
297 CHANGE_RULE *change_rules = NULL;
300 void do_cr_reset(void)
304 while (change_rules) {
305 next = change_rules->next;
306 free((char *) change_rules->type);
313 static unsigned char cvt_byte(const char *s)
318 value = strtoul(s,&end,0);
319 if (value > 255 || *end) cfg_error("\"%s\" is not a byte value",s);
324 static void add_type(const char *type,int normal,int hidden)
328 for (rule = change_rules; rule; rule = rule->next)
329 if (!strcasecmp(rule->type,type))
330 die("Duplicate type name: \"%s\"",type);
331 rule = alloc_t(CHANGE_RULE);
332 rule->type = stralloc(type);
333 rule->normal = normal == -1 ? hidden ^ HIDDEN_OFF : normal;
334 rule->hidden = hidden == -1 ? normal ^ HIDDEN_OFF : hidden;
335 rule->next = change_rules;
340 void do_cr_type(void)
342 const char *normal,*hidden;
344 cfg_init(cf_change_rule);
345 (void) cfg_parse(cf_change_rule);
346 normal = cfg_get_strg(cf_change_rule,"normal");
347 hidden = cfg_get_strg(cf_change_rule,"hidden");
349 add_type(cfg_get_strg(cf_change_rules,"type"),cvt_byte(normal),
350 hidden ? cvt_byte(hidden) : -1);
353 cfg_error("At least one of NORMAL and HIDDEN must be present");
354 add_type(cfg_get_strg(cf_change_rules,"type"),cvt_byte(hidden),-1);
356 cfg_unset(cf_change_rules,"type");
362 cfg_init(cf_change_rules);
363 (void) cfg_parse(cf_change_rules);
367 #if defined(LCF_REWRITE_TABLE) && !defined(LCF_READONLY)
372 * +------+------+------+------+
373 * |drive |offset|expect| set |
374 * +------+------+------+------+
378 static void add_rule(unsigned char bios,unsigned char offset,
379 unsigned char expect,unsigned char set)
383 if (curr_prt_map == PRTMAP_SIZE)
384 cfg_error("Too many change rules (more than %d)",PRTMAP_SIZE);
386 printf(" Adding rule: disk 0x%02x, offset 0x%x, 0x%02x -> 0x%02x\n",
387 bios,PART_TABLE_OFFSET+offset,expect,set);
388 prt_map[curr_prt_map] = (set << 24) | (expect << 16) | (offset << 8) | bios;
389 for (i = 0; i < curr_prt_map; i++) {
390 if (prt_map[i] == prt_map[curr_prt_map])
391 die("Repeated rule: disk 0x%02x, offset 0x%x, 0x%02x -> 0x%02x",
392 bios,PART_TABLE_OFFSET+offset,expect,set);
393 if ((prt_map[i] & 0xffff) == ((offset << 8) | bios) &&
394 (prt_map[i] >> 24) == expect)
395 die("Redundant rule: disk 0x%02x, offset 0x%x: 0x%02x -> 0x%02x "
396 "-> 0x%02x",bios,PART_TABLE_OFFSET+offset,
397 (prt_map[i] >> 16) & 0xff,expect,set);
405 static int has_partition;
407 static CHANGE_RULE *may_change(unsigned char sys_ind)
409 CHANGE_RULE *cr = change_rules;
412 if (cr->normal == sys_ind || cr->hidden == sys_ind) return cr;
419 void do_cr_auto(void)
423 char *table, *table2, *other;
424 int partition, pfd, i, j;
425 struct partition part_table[PART_MAX];
427 if (autoauto) has_partition = 0;
428 other = identify ? cfg_get_strg(cf_identify, "other")
429 : cfg_get_strg(cf_top, "other");
430 if (verbose > 4) printf("do_cr_auto: other=%s has_partition=%d\n",
431 other, has_partition);
433 i = other[strlen(other)-1] - '0';
434 if (i>PART_MAX || i<1) return;
436 table = cfg_get_strg(cf_other,"table");
437 table2 = boot_mbr(other, 1); /* get possible default */
438 if (!table) table = table2;
440 if (!table && autoauto) return;
441 if (table && autoauto && !table2) cfg_error("TABLE may not be specified");
443 if (has_partition) cfg_error("AUTOMATIC must be before PARTITION");
444 if (!table) cfg_error("TABLE must be set to use AUTOMATIC");
447 if (stat(table,&st) < 0) die("stat %s: %s",table,strerror(errno));
448 geo_get(&geo,st.st_rdev & D_MASK(st.st_rdev),-1,1);
449 partition = st.st_rdev & P_MASK(st.st_rdev);
450 if (!S_ISBLK(st.st_mode) || partition)
451 cfg_error("\"%s\" doesn't contain a primary partition table",table);
452 pfd = open(table, O_RDONLY);
453 if (pfd<0) die("Cannot open %s", table);
454 if (lseek(pfd, PART_TABLE_OFFSET, SEEK_SET)!=PART_TABLE_OFFSET)
455 die("Cannot seek to partition table of %s", table);
456 if (read(pfd, part_table, sizeof(part_table))!=sizeof(part_table))
457 die("Cannot read Partition Table of %s", table);
459 partition = other[strlen(other)-1] - '0';
460 if (verbose > 3) printf("partition = %d\n", partition);
461 for (j=i=0; i<PART_MAX; i++)
462 if (may_change(part_table[i].sys_ind)) j++;
465 #if defined(LCF_REWRITE_TABLE) && !defined(LCF_READONLY)
466 for (i=0; i<PART_MAX; i++) {
468 if ((cr=may_change(part_table[i].sys_ind))) {
469 j = i*PARTITION_ENTRY + PART_TYPE_ENT_OFF;
471 warn("CHANGE AUTOMATIC assumed after \"other=%s\"", other);
472 autoauto = 0; /* suppress further warnings */
474 if (i == partition-1)
475 add_rule(geo.device, j, cr->hidden, cr->normal);
477 add_rule(geo.device, j, cr->normal, cr->hidden);
481 warn("This LILO is compiled without REWRITE_TABLE;\n"
482 " unable to generate CHANGE/AUTOMATIC change-rules");
488 void do_cr_part(void)
493 int partition,part_base;
495 tmp = cfg_get_strg(cf_change,"partition");
496 if (stat(tmp,&st) < 0) die("stat %s: %s",tmp,strerror(errno));
497 geo_get(&geo,st.st_rdev & D_MASK(st.st_rdev),-1,1);
498 partition = st.st_rdev & P_MASK(st.st_rdev);
499 if (!S_ISBLK(st.st_mode) || !partition || partition > PART_MAX)
500 cfg_error("\"%s\" isn't a primary partition",tmp);
501 part_base = (partition-1)*PARTITION_ENTRY;
503 cfg_init(cf_change_dsc);
504 (void) cfg_parse(cf_change_dsc);
505 tmp = cfg_get_strg(cf_change_dsc,"set");
507 #if defined(LCF_REWRITE_TABLE) && !defined(LCF_READONLY)
512 here = (void*)NULL; /* quiet GCC */
513 hidden = 0; /* quiet GCC */
514 if (strlen(tmp) < 7 || !(here = strrchr(tmp,'_')) ||
515 ((hidden = strcasecmp(here+1,"normal")) &&
516 strcasecmp(here+1,"hidden")))
517 cfg_error("Type name must end with _normal or _hidden");
519 for (walk = change_rules; walk; walk = walk->next)
520 if (!strcasecmp(walk->type,tmp)) break;
521 if (!walk) cfg_error("Unrecognized type name");
522 add_rule(geo.device,part_base+PART_TYPE_ENT_OFF,hidden ? walk->normal :
523 walk->hidden,hidden ? walk->hidden : walk->normal);
525 die("This LILO is compiled without REWRITE_TABLE and doesn't support "
529 if (cfg_get_flag(cf_change_dsc,"activate")) {
530 #if defined(LCF_REWRITE_TABLE) && !defined(LCF_READONLY)
531 add_rule(geo.device,part_base+PART_ACT_ENT_OFF,0x00,0x80);
532 if (cfg_get_flag(cf_change_dsc,"deactivate"))
533 cfg_error("ACTIVATE and DEACTIVATE are incompatible");
535 die("This LILO is compiled without REWRITE_TABLE and doesn't support "
536 "the ACTIVATE option");
539 if (cfg_get_flag(cf_change_dsc,"deactivate"))
540 #if defined(LCF_REWRITE_TABLE) && !defined(LCF_READONLY)
541 add_rule(geo.device,part_base+PART_ACT_ENT_OFF,0x80,0x00);
543 die("This LILO is compiled without REWRITE_TABLE and doesn't support "
544 "the DEACTIVATE option");
546 cfg_unset(cf_change,"partition");
554 (void) cfg_parse(cf_change);
558 void preload_types(void)
560 #if 0 /* don't know if it makes sense to add these too */
561 add_type("Netware", 0x64, 0x74);
562 add_type("OS2_BM", 0x0a, 0x1a);
564 add_type("OS2_HPFS", 0x07, 0x17);
566 add_type("FAT16_lba", PART_FAT16_LBA, -1);
567 add_type("FAT32_lba", PART_FAT32_LBA, -1);
568 add_type("FAT32", PART_FAT32, -1);
569 add_type("NTFS", PART_NTFS, -1);
570 add_type("DOS16_big", PART_DOS16_BIG, -1);
571 add_type("DOS16_small", PART_DOS16_SMALL, -1);
572 add_type("DOS12", PART_DOS12, -1);
577 #define PART_BEGIN 0x1be
580 #define PART_ACTIVE 0x80
581 #define PART_INACTIVE 0
584 void do_activate(char *part, char *which)
587 int part_max, count, number, fd;
588 struct partition pt [PART_MAX_MAX+1];
589 long long daddr [PART_MAX_MAX+1];
592 part_max = read_partitions(part, extended_pt ? PART_MAX_MAX : 0,
594 /* printf("part_max=%d\n", part_max); */
595 if (!which) { /* one argument: display active partition */
596 for (count=0; count < part_max; count++) {
597 if (pt[count].boot_ind) {
598 printf("%s%d\n",part,count+1);
602 printf("No active partition found on %s\n",part);
605 number = to_number(which);
606 if (number < 0 || number > part_max)
607 die("%s: not a valid partition number (1-%d)",which,part_max);
609 if (number && !pt[number-1].sys_ind) die("Cannot activate an empty partition");
610 number--; /* we are zero-based from here on */
612 if ((fd = open(part, O_RDWR)) < 0)
613 die("open %s: %s",part,strerror(errno));
614 for (count=0; count<part_max; count++) {
615 unsigned char flag = count==number ? PART_ACTIVE : PART_INACTIVE;
616 if (pt[count].sys_ind && pt[count].boot_ind != flag) {
617 pt[count].boot_ind = flag;
618 printf("pt[%d] -> %2x\n", count+1, (int)flag);
619 if (lseek64(fd, daddr[count], SEEK_SET) < 0) die("PT lseek64 failed");
621 if (write(fd, &pt[count], sizeof(pt[0])) != sizeof(pt[0]) )
622 die("PT write failure");
628 printf("The partition table has%s been updated.\n", test ? " *NOT*" : "");
630 printf("No partition table modifications are needed.\n");
634 unsigned char flag, ptype;
636 if ((fd = open(part, !which ? O_RDONLY : O_RDWR)) < 0)
637 die("open %s: %s",part,strerror(errno));
638 if (fstat(fd,&st) < 0) die("stat %s: %s",part,strerror(errno));
639 if (!S_ISBLK(st.st_mode)) die("%s: not a block device",part);
641 printf("st.st_dev = %04X, st.st_rdev = %04X\n",
642 (int)st.st_dev, (int)st.st_rdev);
644 if ((st.st_rdev & has_partitions(st.st_rdev)) != st.st_rdev)
645 die("%s is not a master device with a primary partition table", part);
646 if (!which) { /* one argument: display active partition */
647 for (count = 1; count <= PART_NUM; count++) {
648 if (lseek(fd,PART_BEGIN+(count-1)*PART_SIZE,SEEK_SET) < 0)
649 die("lseek: %s",strerror(errno));
650 if (read(fd,&flag,1) != 1) die("read: %s",strerror(errno));
651 if (flag == PART_ACTIVE) {
652 printf("%s%d\n",part,count);
656 die("No active partition found on %s",part);
658 number = to_number(which);
659 if (number < 0 || number > 4)
660 die("%s: not a valid partition number (1-4)",which);
661 for (count = 1; count <= PART_NUM; count++) {
662 if (lseek(fd,PART_BEGIN+(count-1)*PART_SIZE+4,SEEK_SET) < 0)
663 die("lseek: %s",strerror(errno));
664 if (read(fd,&ptype,1) != 1) die("read: %s",strerror(errno));
665 if (count == number && ptype==0) die("Cannot activate an empty partition");
668 printf("The partition table of %s has *NOT* been updated\n",part);
670 else for (count = 1; count <= PART_NUM; count++) {
671 if (lseek(fd,PART_BEGIN+(count-1)*PART_SIZE,SEEK_SET) < 0)
672 die("lseek: %s",strerror(errno));
673 flag = count == number ? PART_ACTIVE : PART_INACTIVE;
674 if (write(fd,&flag,1) != 1) die("write: %s",strerror(errno));
681 void do_install_mbr(char *part, char *what)
691 if (!what) what = DFL_MBR;
692 extended_pt |= !!strchr(what,'x') || !!strchr(what,'X') || !!strchr(what,'2');
693 if ((fd=open(part,O_RDWR)) < 0) die("Cannot open %s: %s", part,strerror(errno));
694 if (fstat(fd,&st) < 0) die("stat: %s : %s", part,strerror(errno));
695 if (!S_ISBLK(st.st_mode) && !force_fs) die("%s not a block device",part);
696 if (st.st_rdev != (st.st_rdev & has_partitions(st.st_rdev)))
697 die("%s is not a master device with a primary parition table",part);
698 if (read(fd,&buf,SECTOR_SIZE) != SECTOR_SIZE) die("read %s: %s",part, strerror(errno));
700 cp = cfg_get_strg(cf_options,"force-backup");
702 if (!cp) cp = cfg_get_strg(cf_options,"backup");
703 make_backup(cp, i, &buf, st.st_rdev, part);
706 if ((nfd=open(what,O_RDONLY)) < 0) die("Cannot open %s: %s",what,strerror(errno));
707 if (read(nfd,buf,MAX_BOOT_SIZE) != MAX_BOOT_SIZE) die("read %s: %s",what,strerror(errno));
709 memcpy(&buf, extended_pt ? Mbr2.data : Mbr.data, MAX_BOOT_SIZE);
711 buf.boot.boot_ind = BOOT_SIGNATURE;
715 buf.boot.volume_id = 0;
717 if ((cp=cfg_get_strg(cf_options,RAID_EXTRA_BOOT))) {
718 buf.boot.volume_id = strtoul(cp, NULL, 16);
721 } else if (buf.boot.volume_id == 0) {
724 i %= PRIME; /* modulo a prime number; eg, 2551, 9091 */
726 srand(time(NULL)); /* seed the random number generator */
728 *(int*)&buf[PART_TABLE_OFFSET - 6] = rand(); /* insert serial number */
729 if (*(short*)&buf[PART_TABLE_OFFSET - 2] == 0)
730 *(short*)&buf[PART_TABLE_OFFSET - 2] = MAGIC_SERIAL;
732 buf.boot.volume_id = new_serial(st.st_rdev);
733 buf.boot.marker = MAGIC_SERIAL;
737 if (lseek(fd,0,SEEK_SET) != 0) die("seek %s; %s", part, strerror(errno));
739 if (write(fd,&buf,SECTOR_SIZE) != SECTOR_SIZE)
740 die("write %s: %s",part,strerror(errno));
746 printf("The Master Boot Record of %s has %sbeen updated.\n", part, test ? "*NOT* " : "");
752 /* partition table read */
753 int read_partitions(char *part, int max, int *volid,
754 struct partition *p, long long *where)
757 unsigned int second, base;
758 unsigned short boot_sig;
759 struct partition pt[PART_MAX];
764 if ((fd=open(part,O_RDONLY))<0) die("Cannot open '%s'", part);
765 if (fstat(fd,&st)<0) die("Cannot fstat '%s'", part);
766 if (!S_ISBLK(st.st_mode)) die("Not a block device '%s'", part);
768 if (!has_partitions(i) || (P_MASK(i)&i) )
769 die("Not a device with partitions '%s'", part);
771 if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) die("read header");
772 if (!strncmp(hdr.signature, "LILO", 4) && hdr.stage == STAGE_MBR2 &&
773 max == 0) max = PART_MAX_MAX;
774 else if (max == 0) max = PART_MAX;
775 if (lseek(fd, PART_TABLE_OFFSET, SEEK_SET)<0) die("lseek failed");
776 if (read(fd, pt, sizeof(pt)) != sizeof(pt)) die("read pt failed");
777 if ( read(fd, &boot_sig, sizeof(boot_sig)) != sizeof(boot_sig) ||
778 boot_sig != BOOT_SIGNATURE ) die("read boot signature failed");
780 if (lseek(fd, MAX_BOOT_SIZE+2, SEEK_SET)<0) die("lseek vol-ID failed");
781 if (read(fd, volid, sizeof(*volid)) != sizeof(*volid))
782 die("read vol-ID failed");
783 /* printf(" vol-ID: %08X\n", second); */
785 /* printf("%s\n", phead); */
788 for (i=0; i<PART_MAX; i++) {
789 /* print_pt(i+1, pt[i]); */
790 if (is_extd_part(pt[i].sys_ind)) {
791 if (!base) base = pt[i].start_sect;
792 else die("invalid partition table: second extended partition found");
794 if (where) *where++ = PART_TABLE_OFFSET + i*sizeof(*p);
802 daddr = LLSECTORSIZE*(base+second) + PART_TABLE_OFFSET;
803 if (lseek64(fd, daddr, SEEK_SET) < 0)
804 die("secondary lseek64 failed");
805 if (read(fd, pt, sizeof(pt)) != sizeof(pt)) die("secondary read pt failed");
806 if ( read(fd, &boot_sig, sizeof(boot_sig)) != sizeof(boot_sig) ||
807 boot_sig != BOOT_SIGNATURE ) die("read second boot signature failed");
808 /* print_pt(i++, pt[0]); */
809 if (is_extd_part(pt[1].sys_ind)) second=pt[1].start_sect;
813 if (where) *where++ = daddr;
819 if (where) *where = 0;