/*
* $Id$
*
* Copyright (C) 2003-2014 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.build;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.StringTokenizer;
import org.apache.tools.ant.Project;
import org.jnode.driver.ApiNotFoundException;
import org.jnode.driver.Device;
import org.jnode.driver.DriverException;
import org.jnode.driver.block.BlockDeviceAPI;
import org.jnode.driver.block.Geometry;
import org.jnode.driver.block.MappedFSBlockDeviceSupport;
import org.jnode.fs.FileSystemException;
import org.jnode.fs.fat.FatType;
import org.jnode.fs.fat.GrubBootSector;
import org.jnode.fs.fat.GrubFatFormatter;
import org.jnode.partitions.ibm.IBMPartitionTableEntry;
import org.jnode.partitions.ibm.IBMPartitionTypes;
/**
* @author Ewout Prangsma (epr@users.sourceforge.net)
*/
public class BootDiskBuilder extends BootFloppyBuilder {
private File plnFile;
int bytesPerSector = 512;
int spc = 1;
private Geometry geom = new Geometry(64, 16, 32);
private MappedFSBlockDeviceSupport part0;
public BootDiskBuilder() {
}
/**
* Create the actual bootfloppy.
*
* @throws IOException
* @throws DriverException
* @throws FileSystemException
*/
public void createImage() throws IOException, DriverException,
FileSystemException {
super.createImage();
FileWriter fw = new FileWriter(plnFile);
PrintWriter pw = new PrintWriter(fw);
pw.println("DRIVETYPE ide");
pw.println("CYLINDERS " + geom.getCylinders());
pw.println("HEADS " + geom.getHeads());
pw.println("SECTORS " + geom.getSectors());
pw.println("CAPACITY " + geom.getTotalSectors());
pw.println("ACCESS \"" + getDestFile().getCanonicalPath()
+ "\" 0 102400");
pw.flush();
fw.flush();
pw.close();
fw.close();
System.out.println("Wrote " + plnFile);
}
/**
* Format the given device.
*
* @param device
* @throws IOException
*/
protected void formatDevice(Device device) throws IOException {
/* Format the MBR & partitiontable */
GrubBootSector mbr = (GrubBootSector) (createFormatter()
.getBootSector());
IBMPartitionTableEntry pte = mbr.initPartitions(geom, IBMPartitionTypes.PARTTYPE_DOS_FAT16_LT32M);
/*
* System.out.println("partition table:"); for (int i = 0; i < 4; i++) {
* System.out.println("" + i + " " + mbr.getPartition(i)); }
*/
/* Format partition 0 */
part0 = new MappedFSBlockDeviceSupport(device, pte.getStartLba()
* bytesPerSector, pte.getNrSectors() * bytesPerSector);
GrubFatFormatter ff = createFormatter();
ff.setInstallPartition(0x0000FFFF);
ff.format(part0);
GrubBootSector part0bs = (GrubBootSector) ff.getBootSector();
/* Fixup stage2 sector in MBR */
mbr.setStage2Sector(pte.getStartLba() + part0bs.getStage2Sector());
try {
mbr.write(device.getAPI(BlockDeviceAPI.class));
} catch (ApiNotFoundException ex) {
final IOException ioe = new IOException("BlockDeviceAPI not found on device");
ioe.initCause(ex);
throw ioe;
}
//System.out.println("mbr stage2 sector=" + mbr.getStage2Sector());
}
/**
* @return The formatter
* @throws IOException
* @see org.jnode.build.BootFloppyBuilder#createFormatter()
*/
protected GrubFatFormatter createFormatter() throws IOException {
return new GrubFatFormatter(bytesPerSector, spc, geom, FatType.FAT16, 1,
getStage1ResourceName(), getStage2ResourceName());
}
/**
* @return The device length
* @see org.jnode.build.BootFloppyBuilder#getDeviceLength()
*/
protected long getDeviceLength() {
return geom.getTotalSectors() * bytesPerSector;
}
/**
* @return File
*/
public File getPlnFile() {
return plnFile;
}
/**
* Sets the plnFile.
*
* @param plnFile The plnFile to set
*/
public void setPlnFile(File plnFile) {
this.plnFile = plnFile;
}
/**
* @param rootDevice
* @return The device
* @see org.jnode.build.BootFloppyBuilder#getSystemDevice(Device)
*/
protected Device getSystemDevice(Device rootDevice) {
return part0;
}
/**
* Used by ant to set the geometry property.
*
* @param geometryString String in the format 'cylinder/heads/sectors',
* e.g. '64/16/32'.
*/
public void setGeometry(String geometryString) {
try {
log("Setting bootdisk geometry to " + geometryString, Project.MSG_VERBOSE);
StringTokenizer tokenizer = new StringTokenizer(geometryString, "/");
geom = new Geometry(Integer.parseInt(tokenizer.nextToken()),
Integer.parseInt(tokenizer.nextToken()), Integer
.parseInt(tokenizer.nextToken()));
} catch (Exception e) {
throw new IllegalArgumentException(
"Invalid geometry "
+ geometryString
+ ". Must correspond to pattern '<cylinders>/<heads>/<sectors>' e.g. '64/16/32'.");
}
}
}