Commit 7053fb8b authored by Mike Hibler's avatar Mike Hibler

Simple hack to set the type of a DOS partition in the MBR partition table.

Both Linux and BSD versions of fdisk have enough idiosyncratic behaviours
that it got to be a pain to work around them, just to set the type field
for mkextrafs.pl.
parent 815dedf2
......@@ -13,7 +13,7 @@ include $(OBJDIR)/Makeconf
all: server fullclient client
fullclient: tmcc
client: tmcc-nossl findif
client: tmcc-nossl findif dostype
server: tmcd tmcd.restart
include $(TESTBED_SRCDIR)/GNUmakerules
......@@ -91,6 +91,9 @@ tmcc-nossl-debug: tmcc.c decls.h
findif-debug: findif.o
$(CC) $(CFLAGS) -g -o $@ findif.o $(LFLAGS) -static
dostype-debug: dostype.o
$(CC) $(CFLAGS) -g -o $@ dostype.o $(LFLAGS)
ssl.o: ssl.c ssl.h decls.h
version.c: tmcd.c
......@@ -134,7 +137,7 @@ ${OBJDIR}/lib/libtb/%:
cd ${OBJDIR}/lib/tbdb && gmake $<
clean: subdir-clean
rm -f *.o core tmcd tmcc tmcc-nossl findif version.c
rm -f *.o core tmcd tmcc tmcc-nossl findif dostype version.c
subdir-clean:
@$(MAKE) -C $(MDSUBDIR) clean
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2005 University of Utah and the Flux Group.
* All rights reserved.
*/
/*
* Simple hack to set the type of a DOS partition in the MBR partition table.
* Both Linux and BSD versions of fdisk have enough idiosyncratic behaviours
* that it got to be a pain to work around them, just to set the type field
* for mkextrafs.pl.
*
* In Linux, fdisk is interactive only and sfdisk had a habit of trashing BSD
* boot blocks in partition 1 when asked to change the type of partition 4.
*
* In FreeBSD, fdisk wants to validate and correct the size and alignment of
* all the partitions when asked to add the 4th partition. Since FBSD4 and
* FBSD5 have differing ideas about BIOS geometry, the size of the 4th part
* as created by growdisk under the frisbee MFS depended on whether it was
* a FBSD4 or 5 MFS. If the system was then booted under the other flavor
* of FBSD and fdisk were run (from mkextrafs), fdisk would want to tweak
* the size of the final partition. It would do this to the on disk copy
* of the MBR, but not the "in core" version, creating an inconsistancy
* (e.g. with disklabel) that I could not resolve.
*/
#include <stdlib.h>
#include <limits.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#ifndef __CYGWIN__
#include <sys/types.h>
#include <inttypes.h>
#if __FreeBSD__ >= 5
#include <sys/diskmbr.h>
#endif
#endif
#define BOOT_MAGIC 0xAA55
#define DOSBBSECTOR 0
#define DOSPARTOFF 446
#define NDOSPART 4
struct dospart {
uint8_t dp_flag; /* bootstrap flags */
uint8_t dp_shd; /* starting head */
uint8_t dp_ssect; /* starting sector */
uint8_t dp_scyl; /* starting cylinder */
uint8_t dp_typ; /* partition type */
uint8_t dp_ehd; /* end head */
uint8_t dp_esect; /* end sector */
uint8_t dp_ecyl; /* end cylinder */
uint32_t dp_start; /* absolute starting sector number */
uint32_t dp_size; /* partition size in sectors */
};
struct doslabel {
int8_t align[sizeof(short)]; /* Force alignment */
int8_t pad2[DOSPARTOFF];
struct dospart parts[NDOSPART];
uint16_t magic;
};
#define DOSLABELSIZE \
(DOSPARTOFF + NDOSPART*sizeof(struct dospart) + sizeof(uint16_t))
static int force = 0;
static int verbose = 0;
static int fdw = -1;
int fixmbr(int outfd, int slice, int dtype);
static void
usage(void)
{
fprintf(stderr, "usage: "
"dostype [-fv] <diskdev> <DOS_part> <DOS_type>\n"
" -f force setting of type even if already non-zero\n"
" -v verbose output\n"
" <diskdev> disk special file to operate on\n"
" <DOS_part> DOS partition number to change (1-4)\n"
" <DOS_type> DOS partition type to set.\n");
exit(1);
}
int
main(int argc, char **argv)
{
char *disk;
int pnum, ptype;
int ch, fd;
while ((ch = getopt(argc, argv, "fv")) != -1)
switch(ch) {
case 'f':
force++;
break;
case 'v':
verbose++;
break;
case '?':
default:
usage();
}
argc -= optind;
argv += optind;
if (argc < 3)
usage();
disk = argv[0];
pnum = atoi(argv[1]);
if (pnum < 1 || pnum > 4) {
fprintf(stderr, "Invalid partition number '%s'\n", argv[1]);
exit(1);
}
ptype = (int)strtol(argv[2], 0, 0);
if (ptype > 255) {
fprintf(stderr, "Invalid partition type '%s'\n", argv[2]);
exit(1);
}
fd = open(disk, O_RDWR);
#ifdef DIOCSMBR
/*
* Deal with FreeBSD5 funkyness for writing the MBR. You have to use
* an ioctl on the disk to do it. But, you apparently cannot perform
* the ioctl on the "whole disk" device, you have to do it on a slice
* device. So we try opening slice devices until we get one.
*
* This code was derived from fdisk.
*/
if (fd < 0 && errno == EPERM) {
fd = open(disk, O_RDONLY);
if (fd >= 0) {
char sstr[64];
int p;
for (p = 1; p <= 4; p++) {
snprintf(sstr, sizeof sstr, "%ss%d", disk, p);
fdw = open(sstr, O_RDONLY);
if (fdw >= 0)
break;
}
if (fdw < 0)
fd = -1;
}
}
#endif
if (fd < 0) {
perror(disk);
exit(1);
}
return fixmbr(fd, pnum, ptype);
}
int
fixmbr(int outfd, int slice, int dtype)
{
#ifdef __CYGWIN__
fprintf(stderr, "Does't work under Windows yet\n");
return 1;
#else
struct doslabel doslabel;
int cc;
if (lseek(outfd, (off_t)0, SEEK_SET) < 0) {
perror("Could not seek to DOS label");
return 1;
}
if ((cc = read(outfd, doslabel.pad2, DOSLABELSIZE)) < 0) {
perror("Could not read DOS label");
return 1;
}
if (cc != DOSLABELSIZE) {
fprintf(stderr, "Could not get the entire DOS label\n");
return 1;
}
if (doslabel.magic != BOOT_MAGIC) {
fprintf(stderr, "Wrong magic number in DOS partition table\n");
return 1;
}
if (doslabel.parts[slice-1].dp_typ != dtype) {
if (doslabel.parts[slice-1].dp_typ != 0 && !force) {
fprintf(stderr, "part%d: type already set, "
"use '-f' to override\n", slice);
return 1;
}
doslabel.parts[slice-1].dp_typ = dtype;
if (fdw < 0) {
if (lseek(outfd, (off_t)0, SEEK_SET) < 0) {
perror("Could not seek to DOS label");
return 1;
}
cc = write(outfd, doslabel.pad2, DOSLABELSIZE);
if (cc != DOSLABELSIZE) {
perror("Could not write DOS label");
return 1;
}
}
#ifdef DIOCSMBR
else {
if (ioctl(fdw, DIOCSMBR, doslabel.pad2) < 0) {
perror("Could not write DOS label");
return 1;
}
}
#endif
if (verbose)
printf("Set type of DOS partition %d to %d\n",
slice, dtype);
}
return 0;
#endif
}
......@@ -10,6 +10,10 @@ use Fcntl;
use IO::Handle;
use Socket;
# Drag in path stuff so we can find emulab stuff.
BEGIN { require "/etc/emulab/paths.pm"; import emulabpaths; }
my $DOSTYPE = "$BINDIR/dostype";
#
# This file goes in boss:/z/testbed/distributions on boss so that is can
# be passed over via wget to the CDROM on widearea nodes.
......@@ -103,7 +107,14 @@ if ($mounted =~ /^${fsdevice} on (\S*)/) {
" $fsdevice is already mounted on $1\n");
}
my ($sstart, $ssize, $stype) = getslicestuff($disk, $slice);
my $slicesetup = `fdisk -s ${disk} | grep '^[ ]*${slice}:'`;
if ($slicesetup =~ /^[ ]*${slice}:\s*(\d*)\s*(\d*)\s*(0x\S\S)\s*/) {
$stype = hex($3);
}
else {
die("*** $0:\n".
" Could not parse slice $slice fdisk entry!\n");
}
#
# Fail if not forcing and the partition type is non-zero.
......@@ -119,41 +130,19 @@ if (!$forceit) {
}
#
# Set the partition type to BSD
# Set the partition type to BSD if not already set.
#
my $tmpfile = "/tmp/disklabel";
mysystem("echo \"p $slice 165 $sstart $ssize\" | fdisk -f - $disk");
#
# Hmm...fdisk may choose to quietly modify the size downward from what we
# gave it, to ensure "cylinder alignment". (It may also change the start,
# but we are going to ignore that case as we are completely screwed if
# that happens...) Unfortunately, the modified size doesn't show up
# "in kernel" til we reboot, so the "disklabel auto" command below will
# create a label based on the incorrect larger size. We of course, create
# our filesystem based on the disklabel size, so the result is a filesystem
# that works until you reboot, at which point some of it is outside the
# slice and partition boundary. Bad news.
#
# We use fdisk to reread the partition size. At least fdisk is internally
# consistant and will report the size that it truncated the partition to.
# If fdisk reports a different value than it did originally, we record the
# smaller size which is used later when we edit the disklabel.
#
my ($nsstart, $nssize, $nstype) = getslicestuff($disk, $slice);
if ($nsstart != $sstart || $nstype != 165) {
if ($stype != 165) {
die("*** $0:\n".
" fdisk changed type or start?!\n");
}
if ($nssize < $ssize) {
warn("*** $0: WARNING: lowered partition size from $ssize to $nssize\n");
} else {
$nssize = $ssize;
" No $DOSTYPE program, cannot set type of DOS partition\n")
if (! -e "$DOSTYPE");
mysystem("$DOSTYPE -f /dev/$disk $slice 165");
}
#
# Now create the disklabel
#
my $tmpfile = "/tmp/disklabel";
mysystem("disklabel -w -r $slicedev auto");
mysystem("disklabel -r $slicedev > $tmpfile");
......@@ -179,16 +168,10 @@ foreach my $line (@dl) {
my $pat = q(^ a: );
if (!$done && $line =~ /$pat/) {
$line =~ s/$pat/ e: /;
if ($ssize != $nssize) {
$line =~ s/$ssize/$nssize/;
}
$done = 1;
}
$pat = q(^ c: );
if (!$done && $line =~ /$pat/) {
if ($ssize != $nssize) {
$line =~ s/$ssize/$nssize/;
}
print DL $line;
$line =~ s/$pat/ e: /;
$done = 1;
......@@ -226,24 +209,3 @@ sub mysystem($)
}
return 0
}
sub getslicestuff($$) {
my ($_disk, $_slice) = @_;
my $slicesetup = `fdisk -s ${_disk} | grep '^[ ]*${_slice}:'`;
my $sstart;
my $ssize;
my $stype;
if ($slicesetup =~ /^[ ]*${_slice}:\s*(\d*)\s*(\d*)\s*(0x\S\S)\s*/) {
$sstart = $1;
$ssize = $2;
$stype = hex($3);
}
else {
die("*** $0:\n".
" Could not parse slice $slice fdisk entry!\n");
}
return ($sstart, $ssize, $stype);
}
#!/usr/bin/perl -w
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2004 University of Utah and the Flux Group.
# Copyright (c) 2000-2005 University of Utah and the Flux Group.
# All rights reserved.
#
use English;
......@@ -10,6 +10,10 @@ use Fcntl;
use IO::Handle;
use Socket;
# Drag in path stuff so we can find emulab stuff.
BEGIN { require "/etc/emulab/paths.pm"; import emulabpaths; }
my $DOSTYPE = "$BINDIR/dostype";
sub mysystem($);
sub usage()
......@@ -127,10 +131,10 @@ if (!$forceit) {
# I cannot find the source for sfdisk.
#
if ($stype != 131) {
mysystem("dd if=/dev/hda1 of=/var/tmp/part1.bb bs=8192 count=1");
mysystem("sfdisk --change-id $diskdev $slice 83");
mysystem("dd if=/var/tmp/part1.bb of=/dev/hda1 bs=8192 count=1");
mysystem("rm -f /var/tmp/part1.bb");
die("*** $0:\n".
" No $DOSTYPE program, cannot set type of DOS partition\n")
if (! -e "$DOSTYPE");
mysystem("$DOSTYPE -f /dev/$disk $slice 131");
}
mysystem("mkfs $fsdevice");
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment