Browse Source

rework installation scripts for block devices

Avoid sfdisk, parted and chroot to be more portable.
Compile Host grub in target/tools, only used for ibmx40 target
right now. Add pt - partition table manager from OpenWrt with some
additions and portability fixes.
Cfgfs support missing, coming soon.
Waldemar Brodkorb 13 years ago
parent
commit
8f5add1754
6 changed files with 488 additions and 158 deletions
  1. 152 0
      scripts/install-rb532.sh
  2. 44 156
      scripts/install.sh
  3. 7 1
      target/ibmx40/Makefile
  4. 24 0
      target/tools/grub/Makefile
  5. 5 1
      tools/adk/Makefile
  6. 256 0
      tools/adk/pt.c

+ 152 - 0
scripts/install-rb532.sh

@@ -0,0 +1,152 @@
+#!/usr/bin/env bash
+# This file is part of the OpenADK project. OpenADK is copyrighted
+# material, please see the LICENCE file in the top-level directory.
+
+if [ $(id -u) -ne 0 ];then
+	printf "Installation is only possible as root\n"
+	exit 1
+fi
+
+printf "Checking if sfdisk is installed"
+sfdisk=$(which sfdisk)
+
+if [ ! -z $sfdisk -a -x $sfdisk ];then
+	printf "...okay\n"
+else
+	printf "...failed\n"
+	exit 1
+fi
+
+printf "Checking if parted is installed"
+parted=$(which parted)
+
+if [ ! -z $parted -a -x $parted ];then
+	printf "...okay\n"
+else
+	printf "...failed\n"
+	exit 1
+fi
+
+printf "Checking if mke2fs is installed"
+mke2fs=$(which mke2fs)
+
+if [ ! -z $mke2fs -a -x $mke2fs ];then
+	printf "...okay\n"
+else
+	printf "...failed\n"
+	exit 1
+fi
+
+printf "Checking if tune2fs is installed"
+tune2fs=$(which tune2fs)
+
+if [ ! -z $tune2fs -a -x $tune2fs ];then
+	printf "...okay\n"
+else
+	printf "...failed\n"
+	exit 1
+fi
+
+if [ -z $1 ];then
+	printf "Please give your compact flash or USB device as first parameter\n"
+	exit 1
+else
+	if [ -z $2 ];then
+		printf "Please give your install tar archive as second parameter\n"
+		exit 2
+	fi
+	if [ -f $2 ];then
+		printf "Installing $2 on $1\n"
+	else
+		printf "$2 is not a file, Exiting\n"
+		exit 1
+	fi
+	if [ -z $3 ];then
+		printf "Please give the kernel as third parameter\n"
+		exit 2
+	fi
+	if [ -f $3 ];then
+		printf "Installing $3 on $1\n"
+	else
+		printf "$3 is not a file, Exiting\n"
+		exit 1
+	fi
+	if [ -b $1 ];then
+		printf "Using $1 as CF/USB disk for installation\n"
+		printf "This will destroy all data on $1, are you sure?\n"
+		printf "Type "y" to continue\n"
+		read y
+		if [ "$y" = "y" ];then
+			$sfdisk -l $1 2>&1 |grep 'No medium'
+			if [ $? -eq 0 ];then
+				exit 1
+			else
+				printf "Starting with installation\n"
+			fi
+		else
+			printf "Exiting.\n"
+			exit 1
+		fi
+	else
+		printf "Sorry $1 is not a block device\n"
+		exit 1
+	fi
+fi
+	
+
+if [ $(mount | grep $1| wc -l) -ne 0 ];then
+	printf "Block device $1 is in use, please umount first.\n"
+	exit 1
+fi
+
+
+if [ $($sfdisk -l $1 2>/dev/null|grep Empty|wc -l) -ne 4 ];then
+	printf "Partitions already exist, should I wipe them?\n"
+	printf "Type y to continue\n"
+	read y
+	if [ $y = "y" ];then
+		printf "Wiping existing partitions\n"
+		dd if=/dev/zero of=$1 bs=512 count=1 >/dev/null 2>&1
+	else
+		printf "Exiting.\n"
+		exit 1
+	fi
+fi
+
+printf "Create partition and filesystem for rb532\n"
+rootpart=${1}2
+$parted -s $1 mklabel msdos
+sleep 2
+maxsize=$(env LC_ALL=C $parted $1 -s unit cyl print |awk '/^Disk/ { print $3 }'|sed -e 's/cyl//')
+rootsize=$(($maxsize-2))
+
+$parted -s $1 unit cyl mkpart primary ext2 0 1
+$parted -s $1 unit cyl mkpart primary ext2 1 $rootsize
+$parted -s $1 unit cyl mkpart primary fat32 $rootsize $maxsize
+$parted -s $1 set 1 boot on
+$sfdisk --change-id $1 1 27
+$sfdisk --change-id $1 3 88
+sleep 2
+$mke2fs ${1}2
+sync
+dd if=$3 of=${1}1 bs=2048
+sync
+sleep 2
+$tune2fs -c 0 -i 0 -m 1 ${rootpart} >/dev/null
+if [ $? -eq 0 ];then
+	printf "Successfully disabled filesystem checks on ${rootpart}\n"
+else	
+	printf "Disabling filesystem checks failed, Exiting.\n"
+	exit 1
+fi	
+
+tmp=$(mktemp -d)
+mount -t ext2 ${rootpart} $tmp
+printf "Extracting install archive\n"
+tar -C $tmp -xzpf $2 
+printf "Fixing permissions\n"
+chmod 1777 $tmp/tmp
+chmod 4755 $tmp/bin/busybox
+umount $tmp
+printf "Successfully installed.\n"
+exit 0

+ 44 - 156
scripts/install.sh

@@ -1,26 +1,11 @@
 #!/usr/bin/env bash
-if [ $(id -u) -ne 0 ];then
-	printf "Installation is only possible as root\n"
-	exit 1
-fi
-
-printf "Checking if sfdisk is installed"
-sfdisk=$(which sfdisk)
-
-if [ ! -z $sfdisk -a -x $sfdisk ];then
-	printf "...okay\n"
-else
-	printf "...failed\n"
-	exit 1
-fi
+# This file is part of the OpenADK project. OpenADK is copyrighted
+# material, please see the LICENCE file in the top-level directory.
 
-printf "Checking if parted is installed"
-parted=$(which parted)
+TOPDIR=$(pwd)
 
-if [ ! -z $parted -a -x $parted ];then
-	printf "...okay\n"
-else
-	printf "...failed\n"
+if [ $(id -u) -ne 0 ];then
+	printf "Installation is only possible as root\n"
 	exit 1
 fi
 
@@ -34,27 +19,17 @@ else
 	exit 1
 fi
 
-printf "Checking if tune2fs is installed"
-tune2fs=$(which tune2fs)
-
-if [ ! -z $tune2fs -a -x $tune2fs ];then
-	printf "...okay\n"
-else
-	printf "...failed\n"
-	exit 1
-fi
-
 cfgfs=1
-rb532=0
-while getopts "nr" option
+quiet=0
+while getopts "nq" option
 do
 	case $option in
+		q)
+			quiet=1
+			;;
 		n)
 			cfgfs=0
 			;;
-		r)
-			rb532=1
-			;;
 		*)
 			printf "Option not recognized\n"
 			exit 1
@@ -78,33 +53,12 @@ else
 		printf "$2 is not a file, Exiting\n"
 		exit 1
 	fi
-	if [ $rb532 -eq 1 ];then
-		if [ -z $3 ];then
-			printf "Please give the kernel as third parameter\n"
-			exit 2
-		fi
-		if [ -f $3 ];then
-			printf "Installing $3 on $1\n"
-		else
-			printf "$3 is not a file, Exiting\n"
-			exit 1
-		fi
-	fi
 	if [ -b $1 ];then
 		printf "Using $1 as CF/USB disk for installation\n"
-		printf "This will destroy all data on $1, are you sure?\n"
-		printf "Type "y" to continue\n"
-		read y
-		if [ "$y" = "y" ];then
-			$sfdisk -l $1 2>&1 |grep 'No medium'
-			if [ $? -eq 0 ];then
-				exit 1
-			else
-				printf "Starting with installation\n"
-			fi
-		else
-			printf "Exiting.\n"
-			exit 1
+		if [ $quiet -eq 0 ];then
+			printf "This will destroy all data on $1, are you sure?\n"
+			printf "Type "y" to continue\n"
+			read y
 		fi
 	else
 		printf "Sorry $1 is not a block device\n"
@@ -112,26 +66,11 @@ else
 	fi
 fi
 	
-
 if [ $(mount | grep $1| wc -l) -ne 0 ];then
 	printf "Block device $1 is in use, please umount first.\n"
 	exit 1
 fi
 
-
-if [ $($sfdisk -l $1 2>/dev/null|grep Empty|wc -l) -ne 4 ];then
-	printf "Partitions already exist, should I wipe them?\n"
-	printf "Type y to continue\n"
-	read y
-	if [ $y = "y" ];then
-		printf "Wiping existing partitions\n"
-		dd if=/dev/zero of=$1 bs=512 count=1 >/dev/null 2>&1
-	else
-		printf "Exiting.\n"
-		exit 1
-	fi
-fi
-
 case $2 in
 	wrap*)
 		speed=38400
@@ -141,102 +80,51 @@ case $2 in
 		;;
 esac
 
-if [ $rb532 -ne 0 ];then
-	printf "Create partition and filesystem for rb532\n"
-	rootpart=${1}2
-	$parted -s $1 mklabel msdos
-	sleep 2
-	maxsize=$(env LC_ALL=C $parted $1 -s unit cyl print |awk '/^Disk/ { print $3 }'|sed -e 's/cyl//')
-	rootsize=$(($maxsize-2))
-
-	$parted -s $1 unit cyl mkpart primary ext2 0 1
-	$parted -s $1 unit cyl mkpart primary ext2 1 $rootsize
-	$parted -s $1 unit cyl mkpart primary fat32 $rootsize $maxsize
-	$parted -s $1 set 1 boot on
-	$sfdisk --change-id $1 1 27
-	$sfdisk --change-id $1 3 88
-	sleep 2
-	$mke2fs ${1}2
-	sync
-	dd if=$3 of=${1}1 bs=2048
-	sync
-else
-	rootpart=${1}1
-	if [ $cfgfs -eq 0 ];then
-		printf "Create partition and filesystem without cfgfs\n"
-$sfdisk $1 << EOF
-,,L
-;
-;
-;
-y
-EOF
-		$mke2fs ${rootpart}
-	else
-		printf "Create partition and filesystem with cfgfs\n"
-		$parted -s $1 mklabel msdos
-		sleep 2
-		maxsize=$(env LC_ALL=C $parted $1 -s unit cyl print |awk '/^Disk/ { print $3 }'|sed -e 's/cyl//')
-		rootsize=$(($maxsize-2))
-
-		$parted -s $1 unit cyl mkpart primary ext2 0 $rootsize
-		$parted -s $1 unit cyl mkpart primary fat32 $rootsize $maxsize
-		$parted -s $1 set 1 boot on
-		$sfdisk --change-id $1 2 88
-		$mke2fs ${1}1
-	fi
-fi
-
-if [ $? -eq 0 ];then
-	printf "Successfully created partition ${rootpart}\n"
-else
-	printf "Partition creation failed, Exiting.\n"
-	exit 1
-fi
-
-sleep 2
-$tune2fs -c 0 -i 0 -m 1 ${rootpart} >/dev/null
-if [ $? -eq 0 ];then
-	printf "Successfully disabled filesystem checks on ${rootpart}\n"
-else	
-	printf "Disabling filesystem checks failed, Exiting.\n"
-	exit 1
-fi	
-
+rootpart=${1}1
+pt=$TOPDIR/bin/tools/pt
+# get sector size from block device
+maxsector=$(sudo $pt -g $1)
+head=16
+sect=63
+rsize=$(($maxsector / 2))
+
+printf "Creating partition table ...\n"
+table=$(mktemp)
+# generate partition table
+$pt -o $table -s $sect -h $head -p ${rsize}K
+# write partition table to block device
+dd if=$table of=$1 bs=512 count=1 2> /dev/null
+printf "Creating ext2 filesystem ...\n"
+$mke2fs -q ${1}1
+
+printf "Extracting install archive ...\n"
 tmp=$(mktemp -d)
 mount -t ext2 ${rootpart} $tmp
-printf "Extracting install archive\n"
 tar -C $tmp -xzpf $2 
-printf "Fixing permissions\n"
+printf "Fixing permissions ...\n"
 chmod 1777 $tmp/tmp
 chmod 4755 $tmp/bin/busybox
 
-if [ $rb532 -eq 0 ];then
-	printf "Installing GRUB bootloader\n"
-	mkdir -p $tmp/boot/grub
-	mount -o bind /dev $tmp/dev
-	chroot $tmp mount -t proc /proc /proc
-	chroot $tmp mount -t sysfs /sys /sys
+printf "Installing GRUB bootloader ...\n"
+mkdir -p $tmp/boot/grub
 cat << EOF > $tmp/boot/grub/grub.cfg
 set default=0
 set timeout=1
-serial --unit=0 --speed=$speed
-terminal_output serial 
-terminal_input serial 
+terminal_output console
+terminal_input console
 
 menuentry "GNU/Linux (OpenADK)" {
 	insmod ext2
 	set root=(hd0,1)
-	linux /boot/vmlinuz-adk root=/dev/sda1 ro init=/init console=ttyS0,$speed console=tty0 panic=10
+	linux /boot/vmlinuz-adk init=/init
 }
 EOF
-	chroot $tmp grub-install $1
-	umount $tmp/proc
-	umount $tmp/sys
-	umount $tmp/dev
-fi
-
+./bin/tools/sbin/grub-install \
+	--grub-setup=./bin/tools/sbin/grub-setup \
+	--grub-mkimage=./bin/tools/bin/grub-mkimage \
+	--grub-mkdevicemap=./bin/tools/sbin/grub-mkdevicemap \
+	--no-floppy --root-directory=$tmp $1
 umount $tmp
-
 printf "Successfully installed.\n"
+rm -rf $tmp
 exit 0

+ 7 - 1
target/ibmx40/Makefile

@@ -7,6 +7,12 @@ include $(TOPDIR)/mk/modules.mk
 include $(TOPDIR)/mk/kernel-build.mk
 include $(TOPDIR)/mk/image.mk
 
+$(TOOLS_BUILD_DIR):
+	mkdir -p $(TOOLS_BUILD_DIR)
+
+tools-compile: $(TOOLS_BUILD_DIR)
+	$(MAKE) -C ../tools/grub prepare compile install
+
 KERNEL:=$(LINUX_DIR)/arch/x86/boot/bzImage
 
 createinitcrypt:
@@ -26,7 +32,7 @@ imageinstall: $(BIN_DIR)/$(ROOTFSTARBALL)
 	@echo "The RootFS tarball is: $(BIN_DIR)/$(ROOTFSTARBALL)"
 endif
 ifeq ($(FS),usb)
-imageinstall: $(BIN_DIR)/$(ROOTFSTARBALL)
+imageinstall: tools-compile $(BIN_DIR)/$(ROOTFSTARBALL)
 	@echo "The RootFS tarball is: $(BIN_DIR)/$(ROOTFSTARBALL)"
 	@echo "To install everything to USB use scripts/install.sh"
 endif

+ 24 - 0
target/tools/grub/Makefile

@@ -0,0 +1,24 @@
+# This file is part of the OpenADK project. OpenADK is copyrighted
+# material, please see the LICENCE file in the top-level directory.
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=		grub
+PKG_VERSION:=		1.98
+PKG_RELEASE:=		1
+PKG_MD5SUM:=		c0bcf60e524739bb64e3a2d4e3732a59
+PKG_SITES:=		ftp://alpha.gnu.org/gnu/grub/
+
+include ../rules.mk
+
+$(WRKBUILD)/.compiled: ${WRKDIST}/.prepared
+	cd $(WRKBUILD) && ./configure --prefix=$(TOPDIR)/bin/tools
+	$(MAKE) -C $(WRKBUILD)
+	touch $@
+
+$(TOPDIR)/bin/tools/bin/grub-install: $(WRKBUILD)/.compiled
+	$(MAKE) -C $(WRKBUILD) install
+
+install: $(TOPDIR)/bin/tools/bin/grub-install
+
+include $(TOPDIR)/mk/tools.mk

+ 5 - 1
tools/adk/Makefile

@@ -9,6 +9,10 @@ ${TOPDIR}/bin/tools/depmaker:
 ${TOPDIR}/bin/tools/pkgrebuild:
 	$(HOSTCC) -o $(TOPDIR)/bin/tools/pkgrebuild pkgrebuild.c strmap.c
 
-install: ${TOPDIR}/bin/tools/depmaker ${TOPDIR}/bin/tools/pkgrebuild
+${TOPDIR}/bin/tools/pt:
+	$(HOSTCC) -o $(TOPDIR)/bin/tools/pt pt.c
+
+install: ${TOPDIR}/bin/tools/depmaker ${TOPDIR}/bin/tools/pkgrebuild \
+	$(TOPDIR)/bin/tools/pt
 
 include $(TOPDIR)/mk/tools.mk

+ 256 - 0
tools/adk/pt.c

@@ -0,0 +1,256 @@
+/* 
+ * pt - partition table utility
+ * Copyright (C) 2010 by Waldemar Brodkorb <wbx@openadk.org>
+ * 
+ * just adds some required code to ptgen - partition table generator
+ * Copyright (C) 2006 by Felix Fietkau <nbd@openwrt.org>
+ *
+ * uses parts of afdisk
+ * Copyright (C) 2002 by David Roetzel <david@roetzel.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program 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 General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#if defined(__linux__)
+#include <linux/fs.h>
+#endif
+
+#if defined(__APPLE__)
+#include <sys/disk.h>
+#define BLKGETSIZE DKIOCGETBLOCKCOUNT
+#endif
+
+#define bswap16(x) ( \
+	 ((((x)    )&(unsigned int)0xff)<< 8) \
+	|((((x)>> 8)&(unsigned int)0xff)    ) \
+)
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define cpu_to_le16(x) bswap16(x)
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+#define cpu_to_le16(x) (x)
+#else
+#error unknown endianness!
+#endif
+
+/* Partition table entry */
+struct pte { 
+	unsigned char active;
+	unsigned char chs_start[3];
+	unsigned char type;
+	unsigned char chs_end[3];
+	unsigned int start;
+	unsigned int length;
+};
+
+struct partinfo {
+	unsigned long size;
+	int type;
+};
+
+int verbose = 0;
+int active = 1;
+int heads = -1;
+int sectors = -1;
+struct partinfo parts[4];
+char *filename = NULL;
+
+/*
+ * get the sector size of the block device
+ *
+ * print the sector size
+ */
+
+static void getmaxsize(char *device) {
+	int fd;
+	unsigned long maxsectors=0;
+
+	fd = open(device, O_RDONLY);
+	ioctl(fd, BLKGETSIZE, &maxsectors);
+	printf("%lu\n", maxsectors);
+	close(fd);
+}
+
+/* 
+ * parse the size argument, which is either
+ * a simple number (K assumed) or
+ * K, M or G
+ *
+ * returns the size in KByte
+ */
+static long to_kbytes(const char *string) {
+	int exp = 0;
+	long result;
+	char *end;
+
+	result = strtoul(string, &end, 0);
+	switch (tolower(*end)) {
+			case 'k' :
+			case '\0' : exp = 0; break;
+			case 'm' : exp = 1; break;
+			case 'g' : exp = 2; break;
+			default: return 0;
+	}
+
+	if (*end)
+		end++;
+
+	if (*end) {
+		fprintf(stderr, "garbage after end of number\n");
+		return 0;
+	}
+
+	/* result: number + 1024^(exp) */
+	return result * ((2 << ((10 * exp) - 1)) ?: 1);
+}
+
+/* convert the sector number into a CHS value for the partition table */
+static void to_chs(long sect, unsigned char chs[3]) {
+	int c,h,s;
+	
+	s = (sect % sectors) + 1;
+	sect = sect / sectors;
+	h = sect % heads;
+	sect = sect / heads;
+	c = sect;
+
+	chs[0] = h;
+	chs[1] = s | ((c >> 2) & 0xC0);
+	chs[2] = c & 0xFF;
+
+	return;
+}
+
+/* round the sector number up to the next cylinder */
+static inline unsigned long round_to_cyl(long sect) {
+	int cyl_size = heads * sectors;
+
+	return sect + cyl_size - (sect % cyl_size); 
+}
+
+/* check the partition sizes and write the partition table */
+static int gen_ptable(int nr)
+{
+	struct pte pte[4];
+	unsigned long sect = 0; 
+	unsigned int start, len;
+	int i, fd, ret = -1;
+
+	memset(pte, 0, sizeof(struct pte) * 4);
+	for (i = 0; i < nr; i++) {
+		if (!parts[i].size) {
+			fprintf(stderr, "Invalid size in partition %d!\n", i);
+			return -1;
+		}
+		pte[i].active = ((i + 1) == active) ? 0x80 : 0;
+		pte[i].type = parts[i].type;
+		pte[i].start = cpu_to_le16(start = sect + sectors);
+		sect = round_to_cyl(start + parts[i].size * 2);
+		pte[i].length = cpu_to_le16(len = sect - start);
+		to_chs(start, pte[i].chs_start);
+		to_chs(start + len - 1, pte[i].chs_end);
+		if (verbose)
+			fprintf(stderr, "Partition %d: start=%u, end=%u, size=%u\n", i, start * 512, (start + len) * 512, len * 512);
+	}
+
+	if ((fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) {
+		fprintf(stderr, "Can't open output file '%s'\n",filename);
+		return -1;
+	}
+
+	lseek(fd, 446, SEEK_SET);
+	if (write(fd, pte, sizeof(struct pte) * 4) != sizeof(struct pte) * 4) {
+		fprintf(stderr, "write failed.\n");
+		goto fail;
+	}
+	lseek(fd, 510, SEEK_SET);
+	if (write(fd, "\x55\xaa", 2) != 2) {
+		fprintf(stderr, "write failed.\n");
+		goto fail;
+	}
+	
+	ret = 0;
+fail:
+	close(fd);
+	return ret;
+}
+
+static void usage(char *prog)
+{
+	fprintf(stderr,	"Usage: %s [-v] -h <heads> -s <sectors> -o <outputfile> [-a 0..4] [[-t <type>] -p <size>...] \n", prog);
+	fprintf(stderr,	"Usage: %s -g <device>\n", prog);
+	exit(1);
+}
+
+int main (int argc, char **argv)
+{
+	char type = 0x83;
+	int ch;
+	int part = 0;
+
+	while ((ch = getopt(argc, argv, "h:s:p:a:t:o:vg:")) != -1) {
+		switch (ch) {
+		case 'o':
+			filename = optarg;
+			break;
+		case 'v':
+			verbose++;
+			break;
+		case 'h':
+			heads = (int) strtoul(optarg, NULL, 0);
+			break;
+		case 's':
+			sectors = (int) strtoul(optarg, NULL, 0);
+			break;
+		case 'p':
+			if (part > 3) {
+				fprintf(stderr, "Too many partitions\n");
+				exit(1);
+			}
+			parts[part].size = to_kbytes(optarg);
+			parts[part++].type = type;
+			break;
+		case 't':
+			type = (char) strtoul(optarg, NULL, 16);
+			break;
+		case 'a':
+			active = (int) strtoul(optarg, NULL, 0);
+			if ((active < 0) || (active > 4))
+				active = 0;
+			break;
+		case 'g':
+			getmaxsize(optarg);
+			exit(0);
+		case '?':
+		default:
+			usage(argv[0]);
+		}
+	}
+	argc -= optind;
+	if (argc || (heads <= 0) || (sectors <= 0) || !filename) 
+		usage(argv[0]);
+	
+	return gen_ptable(part);
+}