Implement a proper block layer with partition support.
[pintos-anon] / src / utils / pintos-mkdisk
index 662b2e57d7eebccdac6ab1173702a8148a25af2a..87b1563e69c517070e81ad32c36adfabdf6df2a5 100755 (executable)
 use strict;
 use warnings;
 use POSIX;
-use Getopt::Long;
+use Getopt::Long qw(:config bundling);
 use Fcntl 'SEEK_SET';
 
-GetOptions ("h|help" => sub { usage (0); })
+# Read Pintos.pm from the same directory as this program.
+BEGIN { my $self = $0; $self =~ s%/+[^/]*$%%; require "$self/Pintos.pm"; }
+
+our ($disk_fn);                        # Output disk file name.
+our (%parts);                  # Partitions.
+our ($format);                 # "partitioned" (default) or "raw"
+our (%geometry);               # IDE disk geometry.
+our ($align);                  # Align partitions on cylinders?
+our ($loader_fn);              # File name of loader.
+our ($include_loader);         # Include loader?
+our (@kernel_args);            # Kernel arguments.
+
+if (grep ($_ eq '--', @ARGV)) {
+    @kernel_args = @ARGV;
+    @ARGV = ();
+    while ((my $arg = shift (@kernel_args)) ne '--') {
+       push (@ARGV, $arg);
+    }
+}
+
+GetOptions ("h|help" => sub { usage (0); },
+
+           "kernel=s" => \&set_part,
+           "filesys=s" => \&set_part,
+           "scratch=s" => \&set_part,
+           "swap=s" => \&set_part,
+
+           "filesys-size=s" => \&set_part,
+           "scratch-size=s" => \&set_part,
+           "swap-size=s" => \&set_part,
+
+           "kernel-from=s" => \&set_part,
+           "filesys-from=s" => \&set_part,
+           "scratch-from=s" => \&set_part,
+           "swap-from=s" => \&set_part,
+
+           "format=s" => \$format,
+           "loader:s" => \&set_loader,
+           "no-loader" => \&set_no_loader,
+           "geometry=s" => \&set_geometry,
+           "align=s" => \&set_align)
   or exit 1;
-usage (1) if @ARGV != 2;
+usage (1) if @ARGV != 1;
+
+$disk_fn = $ARGV[0];
+die "$disk_fn: already exists\n" if -e $disk_fn;
+
+# Sets the loader to copy to the MBR.
+sub set_loader {
+    die "can't specify both --loader and --no-loader\n"
+      if defined ($include_loader) && !$include_loader;
+    $include_loader = 1;
+    $loader_fn = $_[1] if $_[1] ne '';
+}
+
+# Disables copying a loader to the MBR.
+sub set_no_loader {
+    die "can't specify both --loader and --no-loader\n"
+      if defined ($include_loader) && $include_loader;
+    $include_loader = 0;
+}
+
+# Figure out whether to include a loader.
+$include_loader = exists ($parts{KERNEL}) && $format eq 'partitioned'
+  if !defined ($include_loader);
+die "can't write loader to raw disk\n" if $include_loader && $format eq 'raw';
+die "can't write command-line arguments without --loader or --kernel\n"
+  if @kernel_args && !$include_loader;
+print STDERR "warning: --loader only makes sense without --kernel "
+  . "if this disk will be used to load a kernel from another disk\n"
+  if $include_loader && !exists ($parts{KERNEL});
+
+# Open disk.
+my ($disk_handle);
+open ($disk_handle, '>', $disk_fn) or die "$disk_fn: create: $!\n";
 
-my ($disk, $mb) = @ARGV;
-die "$disk: already exists\n" if -e $disk;
-die "\"$mb\" is not a valid size in megabytes\n"
-  if $mb <= 0 || $mb > 1024 || $mb !~ /^\d+(\.\d+)?|\.\d+/;
+# Read loader.
+my ($loader);
+$loader = read_loader ($loader_fn) if $include_loader;
 
-my ($cyl_cnt) = ceil ($mb * 2);
-my ($cyl_bytes) = 512 * 16 * 63;
-my ($bytes) = $cyl_bytes * $cyl_cnt;
+# Write disk.
+my (%disk) = %parts;
+$disk{DISK} = $disk_fn;
+$disk{HANDLE} = $disk_handle;
+$disk{ALIGN} = $align;
+$disk{GEOMETRY} = %geometry;
+$disk{FORMAT} = $format;
+$disk{LOADER} = $loader;
+$disk{ARGS} = \@kernel_args;
+assemble_disk (%disk);
 
-open (DISK, '>', $disk) or die "$disk: create: $!\n";
-sysseek (DISK, $bytes - 1, SEEK_SET) or die "$disk: seek: $!\n";
-syswrite (DISK, "\0", 1) == 1 or die "$disk: write: $!\n";
-close (DISK) or die "$disk: close: $!\n";
+# Done.
+exit 0;
 
 sub usage {
     print <<'EOF';
 pintos-mkdisk, a utility for creating Pintos virtual disks
-Usage: pintos DISKFILE MB
-where DISKFILE is the file to use for the disk
-  and MB is the disk size in (approximate) megabytes.
-Options:
-  -h, --help        Display this help message.
+Usage: pintos-mkdisk [OPTIONS] DISK [-- ARGUMENT...]
+where DISK is the virtual disk to create,
+      each ARGUMENT is inserted into the command line written to DISK,
+  and each OPTION is one of the following options.
+Partition options: (where PARTITION is one of: kernel filesys scratch swap)
+  --PARTITION=FILE         Use a copy of FILE for the given PARTITION
+  --PARTITION-size=SIZE    Create an empty PARTITION of the given SIZE in MB
+  --PARTITION-from=DISK    Use of a copy of the given PARTITION in DISK
+  (There is no --kernel-size option.)
+Output disk options:
+  --format=partitioned     Write partition table to output (default)
+  --format=raw             Do not write partition table to output
+  (Pintos can only use partitioned disks.)
+Partitioned format output options:
+  --loader[=FILE]          Get bootstrap loader from FILE (default: loader.bin
+                           if --kernel option is specified, empty otherwise)
+  --no-loader              Do not include a bootstrap loader
+  --geometry=H,S           Use H head, S sector geometry (default: 16, 63)
+  --geometry=zip           Use 64 head, 32 sector geometry for USB-ZIP boot
+                           per http://syslinux.zytor.com/usbkey.php
+  --align=bochs            Round size to cylinder for Bochs support (default)
+  --align=full             Align partition boundaries to cylinder boundary to
+                           let fdisk guess correct geometry and quiet warnings
+  --align=none             Don't align partitions at all, to save space
+Other options:
+  -h, --help               Display this help message.
 EOF
-    exit (@_);
+    exit ($_[0]);
 }