1 /* partition.c - Partition table handling
3 * Copyright 1992-1998 Werner Almesberger
4 * Copyright 1999-2005 John Coffman
5 * Copyright 2009-2014 Joachim Wiedorn
8 * Licensed under the terms contained in the file 'COPYING'
9 * in the source directory.
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;
104 /* do not check for obsolete OS2_HPFS */
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
120 /* check for SWAP -- last check, as 'bs' is overwritten */
121 else if (*(int*)bs.sector == 0xFFFFFFFEU) {
122 if (lseek(fd, (PAGE_SIZE)-SECTOR_SIZE, SEEK_SET) != (PAGE_SIZE)-SECTOR_SIZE)
123 pdie("part_nowrite lseek:");
124 if (SECTOR_SIZE != read(fd, bs.sector, sizeof(bs)) ) pdie("part_nowrite swap check:");
125 if (!strncmp((char*)bs.sector+SECTOR_SIZE-10,"SWAPSPACE2",10)
126 || !strncmp((char*)bs.sector+SECTOR_SIZE-10,"SWAP-SPACE",10) ) ret=PTW_SWAP;
129 /* didn't recognize the superblock type, so assume it is okay */
134 } /* raid install with X_MBR_ONLY in use */
135 if (verbose>=6) printf("part_nowrite: %d\n", ret);
141 void part_verify(int dev_nr,int type)
145 char backup_file[PATH_MAX+1];
146 int fd, bck_file, part, size, lin_3d, cyl;
147 unsigned int second, base;
148 struct partition part_table[PART_MAX];
149 int mask, i, pe, Linux, dos, mbr;
150 unsigned short boot_sig;
153 if (!has_partitions(dev_nr) || !(mask = P_MASK(dev_nr)) || !(dev_nr & mask)
155 || (dev_nr & mask) > PART_MAX
159 if (verbose >= 4) printf("part_verify: dev_nr=%04x, type=%d\n", dev_nr, type);
160 geo_get(&geo,dev_nr & ~mask,-1,1);
161 fd = dev_open(&dev,dev_nr & ~mask,cfg_get_flag(cf_options,"fix-table")
162 && !test ? O_RDWR : O_RDONLY);
163 part = (pe = dev_nr & mask)-1;
166 if (lseek(fd, 0L, SEEK_SET) != 0 ||
167 read(fd, &bs, sizeof(bs)) != sizeof(bs) ) pdie("bs read");
168 if (*(int*)bs.signature==EX_MAG_HL) mbr = bs.stage;
169 else mbr = STAGE_MBR;
170 } else mbr = STAGE_MBR;
172 if (lseek(fd, PART_TABLE_OFFSET, SEEK_SET) < 0) pdie("lseek partition table");
173 if (!(size = read(fd,(char *) part_table, sizeof(struct partition)*
174 PART_MAX))) die("Short read on partition table");
175 if (size < 0) pdie("read partition table");
176 if ( read(fd, &boot_sig, sizeof(boot_sig)) != sizeof(boot_sig) ||
177 boot_sig != BOOT_SIGNATURE ) die("read boot signature failed");
179 if (verbose>=5) printf("part_verify: part#=%d\n", pe);
182 for (i=0; i<PART_MAX; i++) {
183 if (is_extd_part(part_table[i].sys_ind)) {
184 if (!base) base = part_table[i].start_sect;
185 else die("invalid partition table: second extended partition found");
189 while (i<=pe && base) {
190 if (lseek64(fd, LLSECTORSIZE*(base+second) + PART_TABLE_OFFSET, SEEK_SET) < 0)
191 die("secondary lseek64 failed");
192 if (read(fd, part_table, sizeof(part_table)) != sizeof(part_table)) die("secondary read pt failed");
193 if ( read(fd, &boot_sig, sizeof(boot_sig)) != sizeof(boot_sig) ||
194 boot_sig != BOOT_SIGNATURE ) die("read second boot signature failed");
195 if (is_extd_part(part_table[1].sys_ind)) second=part_table[1].start_sect;
201 if (type && pe>0 && pe<=(mbr==STAGE_MBR2?63:PART_MAX)
202 && !(part_table[part].boot_ind&0x80) )
203 warn("Partition %d on %s is not marked Active.",
206 i = part_table[part].sys_ind;
208 Linux = i == PART_LINUX_MINIX ||
209 i == PART_LINUX_NATIVE ||
210 i == PART_LINUX_LVM ||
214 dos = i == PART_DOS12 ||
215 i == PART_DOS16_SMALL ||
216 i == PART_DOS16_BIG ||
218 i == PART_FAT32_LBA ||
219 i == PART_FAT16_LBA ||
222 if (type && !Linux) {
223 warn("partition type 0x%02X"" on device 0x%04X is a dangerous place for\n"
225 part_table[part].sys_ind, dev_nr,
226 dos ? " A DOS/Windows system may be rendered unbootable."
227 "\n The backup copy of this boot sector should be retained."
229 fprintf (errstd, "I will assume that you know what you're doing and I will proceed.\n");
231 if (!dos && !cfg_get_flag(cf_options,"ignore-table"))
232 die("You may proceed by using either '-P ignore' or 'ignore-table'");
235 cyl = part_table[part].cyl+((part_table[part].sector >> 6) << 8);
236 lin_3d = (part_table[part].sector & 63)-1+(part_table[part].head+
237 cyl*geo.heads)*geo.sectors;
238 if (pe <= PART_MAX &&
239 (lin_3d > part_table[part].start_sect || (lin_3d <
240 part_table[part].start_sect && cyl != BIOS_MAX_CYLS-1)) ) {
241 warn("Device 0x%04X: Inconsistent partition table, %d%s entry",
242 dev_nr & ~mask,part+1,!part ? "st" : part == 1 ? "nd" : part ==
245 fprintf(errstd," CHS address in PT: %d:%d:%d --> LBA (%d)\n",
247 part_table[part].head,
248 part_table[part].sector & 63,
250 cyl = part_table[part].start_sect/geo.sectors/geo.heads;
252 fprintf(errstd," LBA address in PT: %d --> CHS (%d:%d:%d)\n",
253 part_table[part].start_sect,
255 part_table[part].head = (part_table[part].start_sect/geo.sectors) % geo.heads,
256 part_table[part].sector = (part_table[part].start_sect % geo.sectors)+1
258 if (cyl >= BIOS_MAX_CYLS) cyl = BIOS_MAX_CYLS-1;
259 part_table[part].sector |= (cyl >> 8)<<6;
260 part_table[part].cyl = cyl & 0xff;
261 if (!cfg_get_flag(cf_options,"fix-table") && !cfg_get_flag(cf_options,
262 "ignore-table")) die("Either FIX-TABLE or IGNORE-TABLE must be specified\n"
263 "If not sure, first try IGNORE-TABLE (-P ignore)");
264 if (test || cfg_get_flag(cf_options,"ignore-table")) {
265 warn("The partition table is *NOT* being adjusted.");
267 sprintf(backup_file,BACKUP_DIR "/part.%04X",dev_nr & ~mask);
268 if ((bck_file = creat(backup_file,0644)) < 0)
269 die("creat %s: %s",backup_file,strerror(errno));
270 if (!(size = write(bck_file,(char *) part_table,
271 sizeof(struct partition)*PART_MAX)))
272 die("Short write on %s",backup_file);
273 if (size < 0) pdie(backup_file);
274 if (close(bck_file) < 0)
275 die("close %s: %s",backup_file,strerror(errno));
277 printf("Backup copy of partition table in %s\n",backup_file);
278 printf("Writing modified partition table to device 0x%04X\n",
280 if (lseek(fd,PART_TABLE_OFFSET,SEEK_SET) < 0)
281 pdie("lseek partition table");
282 if (!(size = write(fd,(char *) part_table,sizeof(struct partition)*
283 PART_MAX))) die("Short write on partition table");
284 if (size < 0) pdie("write partition table");
291 CHANGE_RULE *change_rules = NULL;
294 void do_cr_reset(void)
298 while (change_rules) {
299 next = change_rules->next;
300 free((char *) change_rules->type);
307 static unsigned char cvt_byte(const char *s)
312 value = strtoul(s,&end,0);
313 if (value > 255 || *end) cfg_error("\"%s\" is not a byte value",s);
318 static void add_type(const char *type,int normal,int hidden)
322 for (rule = change_rules; rule; rule = rule->next)
323 if (!strcasecmp(rule->type,type))
324 die("Duplicate type name: \"%s\"",type);
325 rule = alloc_t(CHANGE_RULE);
326 rule->type = stralloc(type);
327 rule->normal = normal == -1 ? hidden ^ HIDDEN_OFF : normal;
328 rule->hidden = hidden == -1 ? normal ^ HIDDEN_OFF : hidden;
329 rule->next = change_rules;
334 void do_cr_type(void)
336 const char *normal,*hidden;
338 cfg_init(cf_change_rule);
339 (void) cfg_parse(cf_change_rule);
340 normal = cfg_get_strg(cf_change_rule,"normal");
341 hidden = cfg_get_strg(cf_change_rule,"hidden");
343 add_type(cfg_get_strg(cf_change_rules,"type"),cvt_byte(normal),
344 hidden ? cvt_byte(hidden) : -1);
347 cfg_error("At least one of NORMAL and HIDDEN must be present");
348 add_type(cfg_get_strg(cf_change_rules,"type"),cvt_byte(hidden),-1);
350 cfg_unset(cf_change_rules,"type");
356 cfg_init(cf_change_rules);
357 (void) cfg_parse(cf_change_rules);
361 #if defined(LCF_REWRITE_TABLE) && !defined(LCF_READONLY)
366 * +------+------+------+------+
367 * |drive |offset|expect| set |
368 * +------+------+------+------+
372 static void add_rule(unsigned char bios,unsigned char offset,
373 unsigned char expect,unsigned char set)
377 if (curr_prt_map == PRTMAP_SIZE)
378 cfg_error("Too many change rules (more than %d)",PRTMAP_SIZE);
380 printf(" Adding rule: disk 0x%02x, offset 0x%x, 0x%02x -> 0x%02x\n",
381 bios,PART_TABLE_OFFSET+offset,expect,set);
382 prt_map[curr_prt_map] = (set << 24) | (expect << 16) | (offset << 8) | bios;
383 for (i = 0; i < curr_prt_map; i++) {
384 if (prt_map[i] == prt_map[curr_prt_map])
385 die("Repeated rule: disk 0x%02x, offset 0x%x, 0x%02x -> 0x%02x",
386 bios,PART_TABLE_OFFSET+offset,expect,set);
387 if ((prt_map[i] & 0xffff) == ((offset << 8) | bios) &&
388 (prt_map[i] >> 24) == expect)
389 die("Redundant rule: disk 0x%02x, offset 0x%x: 0x%02x -> 0x%02x "
390 "-> 0x%02x",bios,PART_TABLE_OFFSET+offset,
391 (prt_map[i] >> 16) & 0xff,expect,set);
399 static int has_partition;
401 static CHANGE_RULE *may_change(unsigned char sys_ind)
403 CHANGE_RULE *cr = change_rules;
406 if (cr->normal == sys_ind || cr->hidden == sys_ind) return cr;
413 void do_cr_auto(void)
417 char *table, *table2, *other;
418 int partition, pfd, i, j;
419 struct partition part_table[PART_MAX];
421 if (autoauto) has_partition = 0;
422 other = identify ? cfg_get_strg(cf_identify, "other")
423 : cfg_get_strg(cf_top, "other");
424 if (verbose > 4) printf("do_cr_auto: other=%s has_partition=%d\n",
425 other, has_partition);
427 i = other[strlen(other)-1] - '0';
428 if (i>PART_MAX || i<1) return;
430 table = cfg_get_strg(cf_other,"table");
431 table2 = boot_mbr(other, 1); /* get possible default */
432 if (!table) table = table2;
434 if (!table && autoauto) return;
435 if (table && autoauto && !table2) cfg_error("TABLE may not be specified");
437 if (has_partition) cfg_error("AUTOMATIC must be before PARTITION");
438 if (!table) cfg_error("TABLE must be set to use AUTOMATIC");
441 if (stat(table,&st) < 0) die("stat %s: %s",table,strerror(errno));
442 geo_get(&geo,st.st_rdev & D_MASK(st.st_rdev),-1,1);
443 partition = st.st_rdev & P_MASK(st.st_rdev);
444 if (!S_ISBLK(st.st_mode) || partition)
445 cfg_error("\"%s\" doesn't contain a primary partition table",table);
446 pfd = open(table, O_RDONLY);
447 if (pfd<0) die("Cannot open %s", table);
448 if (lseek(pfd, PART_TABLE_OFFSET, SEEK_SET)!=PART_TABLE_OFFSET)
449 die("Cannot seek to partition table of %s", table);
450 if (read(pfd, part_table, sizeof(part_table))!=sizeof(part_table))
451 die("Cannot read Partition Table of %s", table);
453 partition = other[strlen(other)-1] - '0';
454 if (verbose > 3) printf("partition = %d\n", partition);
455 for (j=i=0; i<PART_MAX; i++)
456 if (may_change(part_table[i].sys_ind)) j++;
459 #if defined(LCF_REWRITE_TABLE) && !defined(LCF_READONLY)
460 for (i=0; i<PART_MAX; i++) {
462 if ((cr=may_change(part_table[i].sys_ind))) {
463 j = i*PARTITION_ENTRY + PART_TYPE_ENT_OFF;
465 warn("CHANGE AUTOMATIC assumed after \"other=%s\"", other);
466 autoauto = 0; /* suppress further warnings */
468 if (i == partition-1)
469 add_rule(geo.device, j, cr->hidden, cr->normal);
471 add_rule(geo.device, j, cr->normal, cr->hidden);
475 warn("This LILO is compiled without REWRITE_TABLE;\n"
476 " unable to generate CHANGE/AUTOMATIC change-rules");
482 void do_cr_part(void)
487 int partition,part_base;
489 tmp = cfg_get_strg(cf_change,"partition");
490 if (stat(tmp,&st) < 0) die("stat %s: %s",tmp,strerror(errno));
491 geo_get(&geo,st.st_rdev & D_MASK(st.st_rdev),-1,1);
492 partition = st.st_rdev & P_MASK(st.st_rdev);
493 if (!S_ISBLK(st.st_mode) || !partition || partition > PART_MAX)
494 cfg_error("\"%s\" isn't a primary partition",tmp);
495 part_base = (partition-1)*PARTITION_ENTRY;
497 cfg_init(cf_change_dsc);
498 (void) cfg_parse(cf_change_dsc);
499 tmp = cfg_get_strg(cf_change_dsc,"set");
501 #if defined(LCF_REWRITE_TABLE) && !defined(LCF_READONLY)
506 here = (void*)NULL; /* quiet GCC */
507 hidden = 0; /* quiet GCC */
508 if (strlen(tmp) < 7 || !(here = strrchr(tmp,'_')) ||
509 ((hidden = strcasecmp(here+1,"normal")) &&
510 strcasecmp(here+1,"hidden")))
511 cfg_error("Type name must end with _normal or _hidden");
513 for (walk = change_rules; walk; walk = walk->next)
514 if (!strcasecmp(walk->type,tmp)) break;
515 if (!walk) cfg_error("Unrecognized type name");
516 add_rule(geo.device,part_base+PART_TYPE_ENT_OFF,hidden ? walk->normal :
517 walk->hidden,hidden ? walk->hidden : walk->normal);
519 die("This LILO is compiled without REWRITE_TABLE and doesn't support "
523 if (cfg_get_flag(cf_change_dsc,"activate")) {
524 #if defined(LCF_REWRITE_TABLE) && !defined(LCF_READONLY)
525 add_rule(geo.device,part_base+PART_ACT_ENT_OFF,0x00,0x80);
526 if (cfg_get_flag(cf_change_dsc,"deactivate"))
527 cfg_error("ACTIVATE and DEACTIVATE are incompatible");
529 die("This LILO is compiled without REWRITE_TABLE and doesn't support "
530 "the ACTIVATE option");
533 if (cfg_get_flag(cf_change_dsc,"deactivate"))
534 #if defined(LCF_REWRITE_TABLE) && !defined(LCF_READONLY)
535 add_rule(geo.device,part_base+PART_ACT_ENT_OFF,0x80,0x00);
537 die("This LILO is compiled without REWRITE_TABLE and doesn't support "
538 "the DEACTIVATE option");
540 cfg_unset(cf_change,"partition");
548 (void) cfg_parse(cf_change);
552 void preload_types(void)
554 /* add_type("OS2_HPFS", 0x07, 0x17); */
555 add_type("FAT16_lba", PART_FAT16_LBA, -1);
556 add_type("FAT32_lba", PART_FAT32_LBA, -1);
557 add_type("FAT32", PART_FAT32, -1);
558 add_type("NTFS", PART_NTFS, -1);
559 add_type("DOS16_big", PART_DOS16_BIG, -1);
560 add_type("DOS16_small", PART_DOS16_SMALL, -1);
561 add_type("DOS12", PART_DOS12, -1);
566 #define PART_BEGIN 0x1be
569 #define PART_ACTIVE 0x80
570 #define PART_INACTIVE 0
573 void do_activate(char *part, char *which)
576 int part_max, count, number, fd;
577 struct partition pt [PART_MAX_MAX+1];
578 long long daddr [PART_MAX_MAX+1];
581 part_max = read_partitions(part, extended_pt ? PART_MAX_MAX : 0,
583 /* printf("part_max=%d\n", part_max); */
584 if (!which) { /* one argument: display active partition */
585 for (count=0; count < part_max; count++) {
586 if (pt[count].boot_ind) {
587 printf("%s%d\n",part,count+1);
591 printf("No active partition found on %s\n",part);
594 number = to_number(which);
595 if (number < 0 || number > part_max)
596 die("%s: not a valid partition number (1-%d)",which,part_max);
598 if (number && !pt[number-1].sys_ind) die("Cannot activate an empty partition");
599 number--; /* we are zero-based from here on */
601 if ((fd = open(part, O_RDWR)) < 0)
602 die("open %s: %s",part,strerror(errno));
603 for (count=0; count<part_max; count++) {
604 unsigned char flag = count==number ? PART_ACTIVE : PART_INACTIVE;
605 if (pt[count].sys_ind && pt[count].boot_ind != flag) {
606 pt[count].boot_ind = flag;
607 printf("pt[%d] -> %2x\n", count+1, (int)flag);
608 if (lseek64(fd, daddr[count], SEEK_SET) < 0) die("PT lseek64 failed");
610 if (write(fd, &pt[count], sizeof(pt[0])) != sizeof(pt[0]) )
611 die("PT write failure");
617 printf("The partition table has%s been updated.\n", test ? " *NOT*" : "");
619 printf("No partition table modifications are needed.\n");
623 unsigned char flag, ptype;
625 if ((fd = open(part, !which ? O_RDONLY : O_RDWR)) < 0)
626 die("open %s: %s",part,strerror(errno));
627 if (fstat(fd,&st) < 0) die("stat %s: %s",part,strerror(errno));
628 if (!S_ISBLK(st.st_mode)) die("%s: not a block device",part);
630 printf("st.st_dev = %04X, st.st_rdev = %04X\n",
631 (int)st.st_dev, (int)st.st_rdev);
633 if ((st.st_rdev & has_partitions(st.st_rdev)) != st.st_rdev)
634 die("%s is not a master device with a primary partition table", part);
635 if (!which) { /* one argument: display active partition */
636 for (count = 1; count <= PART_NUM; count++) {
637 if (lseek(fd,PART_BEGIN+(count-1)*PART_SIZE,SEEK_SET) < 0)
638 die("lseek: %s",strerror(errno));
639 if (read(fd,&flag,1) != 1) die("read: %s",strerror(errno));
640 if (flag == PART_ACTIVE) {
641 printf("%s%d\n",part,count);
645 die("No active partition found on %s",part);
647 number = to_number(which);
648 if (number < 0 || number > 4)
649 die("%s: not a valid partition number (1-4)",which);
650 for (count = 1; count <= PART_NUM; count++) {
651 if (lseek(fd,PART_BEGIN+(count-1)*PART_SIZE+4,SEEK_SET) < 0)
652 die("lseek: %s",strerror(errno));
653 if (read(fd,&ptype,1) != 1) die("read: %s",strerror(errno));
654 if (count == number && ptype==0) die("Cannot activate an empty partition");
657 printf("The partition table of %s has *NOT* been updated\n",part);
659 else for (count = 1; count <= PART_NUM; count++) {
660 if (lseek(fd,PART_BEGIN+(count-1)*PART_SIZE,SEEK_SET) < 0)
661 die("lseek: %s",strerror(errno));
662 flag = count == number ? PART_ACTIVE : PART_INACTIVE;
663 if (write(fd,&flag,1) != 1) die("write: %s",strerror(errno));
670 void do_install_mbr(char *part, char *what)
680 if (!what) what = DFL_MBR;
681 extended_pt |= !!strchr(what,'x') || !!strchr(what,'X') || !!strchr(what,'2');
682 if ((fd=open(part,O_RDWR)) < 0) die("Cannot open %s: %s", part,strerror(errno));
683 if (fstat(fd,&st) < 0) die("stat: %s : %s", part,strerror(errno));
684 if (!S_ISBLK(st.st_mode) && !force_fs) die("%s not a block device",part);
685 if (st.st_rdev != (st.st_rdev & has_partitions(st.st_rdev)))
686 die("%s is not a master device with a primary parition table",part);
687 if (read(fd,&buf,SECTOR_SIZE) != SECTOR_SIZE) die("read %s: %s",part, strerror(errno));
689 cp = cfg_get_strg(cf_options,"force-backup");
691 if (!cp) cp = cfg_get_strg(cf_options,"backup");
692 make_backup(cp, i, &buf, st.st_rdev, part);
695 if ((nfd=open(what,O_RDONLY)) < 0) die("Cannot open %s: %s",what,strerror(errno));
696 if (read(nfd,buf,MAX_BOOT_SIZE) != MAX_BOOT_SIZE) die("read %s: %s",what,strerror(errno));
698 memcpy(&buf, extended_pt ? Mbr2.data : Mbr.data, MAX_BOOT_SIZE);
700 buf.boot.boot_ind = BOOT_SIGNATURE;
704 buf.boot.volume_id = 0;
706 if ((cp=cfg_get_strg(cf_options,RAID_EXTRA_BOOT))) {
707 buf.boot.volume_id = strtoul(cp, NULL, 16);
710 } else if (buf.boot.volume_id == 0) {
713 i %= PRIME; /* modulo a prime number; eg, 2551, 9091 */
715 srand(time(NULL)); /* seed the random number generator */
717 *(int*)&buf[PART_TABLE_OFFSET - 6] = rand(); /* insert serial number */
718 if (*(short*)&buf[PART_TABLE_OFFSET - 2] == 0)
719 *(short*)&buf[PART_TABLE_OFFSET - 2] = MAGIC_SERIAL;
721 buf.boot.volume_id = new_serial(st.st_rdev);
722 buf.boot.marker = MAGIC_SERIAL;
726 if (lseek(fd,0,SEEK_SET) != 0) die("seek %s; %s", part, strerror(errno));
728 if (write(fd,&buf,SECTOR_SIZE) != SECTOR_SIZE)
729 die("write %s: %s",part,strerror(errno));
735 printf("The Master Boot Record of %s has %sbeen updated.\n", part, test ? "*NOT* " : "");
741 /* partition table read */
742 int read_partitions(char *part, int max, int *volid,
743 struct partition *p, long long *where)
746 unsigned int second, base;
747 unsigned short boot_sig;
748 struct partition pt[PART_MAX];
753 if ((fd=open(part,O_RDONLY))<0) die("Cannot open '%s'", part);
754 if (fstat(fd,&st)<0) die("Cannot fstat '%s'", part);
755 if (!S_ISBLK(st.st_mode)) die("Not a block device '%s'", part);
757 if (!has_partitions(i) || (P_MASK(i)&i) )
758 die("Not a device with partitions '%s'", part);
760 if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) die("read header");
761 if (!strncmp(hdr.signature, "LILO", 4) && hdr.stage == STAGE_MBR2 &&
762 max == 0) max = PART_MAX_MAX;
763 else if (max == 0) max = PART_MAX;
764 if (lseek(fd, PART_TABLE_OFFSET, SEEK_SET)<0) die("lseek failed");
765 if (read(fd, pt, sizeof(pt)) != sizeof(pt)) die("read pt failed");
766 if ( read(fd, &boot_sig, sizeof(boot_sig)) != sizeof(boot_sig) ||
767 boot_sig != BOOT_SIGNATURE ) die("read boot signature failed");
769 if (lseek(fd, MAX_BOOT_SIZE+2, SEEK_SET)<0) die("lseek vol-ID failed");
770 if (read(fd, volid, sizeof(*volid)) != sizeof(*volid))
771 die("read vol-ID failed");
772 /* printf(" vol-ID: %08X\n", second); */
774 /* printf("%s\n", phead); */
777 for (i=0; i<PART_MAX; i++) {
778 /* print_pt(i+1, pt[i]); */
779 if (is_extd_part(pt[i].sys_ind)) {
780 if (!base) base = pt[i].start_sect;
781 else die("invalid partition table: second extended partition found");
783 if (where) *where++ = PART_TABLE_OFFSET + i*sizeof(*p);
791 daddr = LLSECTORSIZE*(base+second) + PART_TABLE_OFFSET;
792 if (lseek64(fd, daddr, SEEK_SET) < 0)
793 die("secondary lseek64 failed");
794 if (read(fd, pt, sizeof(pt)) != sizeof(pt)) die("secondary read pt failed");
795 if ( read(fd, &boot_sig, sizeof(boot_sig)) != sizeof(boot_sig) ||
796 boot_sig != BOOT_SIGNATURE ) die("read second boot signature failed");
797 /* print_pt(i++, pt[0]); */
798 if (is_extd_part(pt[1].sys_ind)) second=pt[1].start_sect;
802 if (where) *where++ = daddr;
808 if (where) *where = 0;