Эх сурвалжийг харах

new GRUB2 installation script, derived from MirBSD bootblocks

Signed-off-by: Thorsten Glaser <tg@mirbsd.org>
Thorsten Glaser 15 жил өмнө
parent
commit
66c32905a8
3 өөрчлөгдсөн 303 нэмэгдсэн , 353 устгасан
  1. 302 106
      scripts/install.sh
  2. 1 4
      tools/adk/Makefile
  3. 0 243
      tools/adk/pt.c

+ 302 - 106
scripts/install.sh

@@ -1,132 +1,328 @@
 #!/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.
+#-
+# Copyright © 2010
+#	Waldemar Brodkorb <wbx@openadk.org>
+#	Thorsten Glaser <tg@mirbsd.org>
+#
+# Provided that these terms and disclaimer and all copyright notices
+# are retained or reproduced in an accompanying document, permission
+# is granted to deal in this work without restriction, including un‐
+# limited rights to use, publicly perform, distribute, sell, modify,
+# merge, give away, or sublicence.
+#
+# This work is provided “AS IS” and WITHOUT WARRANTY of any kind, to
+# the utmost extent permitted by applicable law, neither express nor
+# implied; without malicious intent or gross negligence. In no event
+# may a licensor, author or contributor be held liable for indirect,
+# direct, other damage, loss, or other issues arising in any way out
+# of dealing in the work, even if advised of the possibility of such
+# damage or existence of a defect, except proven that it results out
+# of said person’s immediate fault when using the work as intended.
+#
+# Alternatively, this work may be distributed under the terms of the
+# General Public License, any version, as published by the Free Soft-
+# ware Foundation.
+#-
+# Prepare a USB stick or CF/SD/MMC card or hard disc for installation
+# of OpenADK:
+# • install a Master Boot Record containing a MirBSD PBR loading GRUB
+# • write GRUB2 core.img just past the MBR
+# • create a root partition with ext2fs and extract the OpenADK image
+#   just built there
+# • create a cfgfs partition
 
 TOPDIR=$(pwd)
+me=$0
 
-if [ $(id -u) -ne 0 ];then
-	printf "Installation is only possible as root\n"
-	exit 1
+case :$PATH: in
+(*:$TOPDIR/bin/tools:*) ;;
+(*) export PATH=$PATH:$TOPDIR/bin/tools ;;
+esac
+
+test -n "$KSH_VERSION" || if ! which mksh >/dev/null 2>&1; then
+	make package=mksh fetch || exit 1
+	df=$(cd package/mksh; TOPDIR="$TOPDIR" gmake show=DISTFILES)
+	mkdir -p build_mksh
+	gzip -dc dl/"$df" | (cd build_mksh; cpio -mid)
+	cd build_mksh/mksh
+	bash Build.sh -r || exit 1
+	cp mksh "$TOPDIR"/bin/tools/
+	cd "$TOPDIR"
+	rm -rf build_mksh
 fi
 
-printf "Checking if mke2fs is installed"
-mke2fs=$(which mke2fs)
+test -n "$KSH_VERSION" || exec mksh "$me" "$@"
+if test -z "$KSH_VERSION"; then
+	echo >&2 Fatal error: could not run myself with mksh!
+	exit 255
+fi
 
-if [ ! -z $mke2fs -a -x $mke2fs ];then
-	printf "...okay\n"
-else
-	printf "...failed\n"
+### run with mksh from here onwards ###
+
+me=${me##*/}
+
+if (( USER_ID )); then
+	print -u2 Installation is only possible as root!
 	exit 1
 fi
 
+TOPDIR=$(realpath .)
+ostype=$(uname -s)
+
 cfgfs=1
 quiet=0
-console=0
 serial=0
-while getopts "nq" option
-do
-	case $option in
-		q)
-			quiet=1
-			;;
-		n)
-			cfgfs=0
-			;;
-		*)
-			printf "Option not recognized\n"
+speed=115200
+
+function usage {
+cat >&2 <<EOF
+Syntax: $me [-c cfgfssize] [±qt] [-s serialspeed] /dev/sdb image
+Defaults: -c 1 -s 115200
+EOF
+	exit $1
+}
+
+while getopts "c:hqs:t" ch; do
+	case $ch {
+	(c)	if (( (cfgfs = OPTARG) < 0 || cfgfs > 5 )); then
+			print -u2 "$me: -c $OPTARG out of bounds"
+			exit 1
+		fi ;;
+	(h)	usage 0 ;;
+	(q)	quiet=1 ;;
+	(+q)	quiet=0 ;;
+	(s)	if [[ $OPTARG != @(96|192|384|576|1152)00 ]]; then
+			print -u2 "$me: serial speed $OPTARG invalid"
 			exit 1
-			;;
-	esac
+		fi
+		speed=$OPTARG ;;
+	(t)	serial=1 ;;
+	(+t)	serial=0 ;;
+	(*)	usage 1 ;;
+	}
 done
-shift $(($OPTIND - 1))
+shift $((OPTIND - 1))
 
+(( $# == 2 )) || usage 1
 
-if [ -z $1 ];then
-	printf "Please give your compact flash or USB device as first parameter\n"
+f=0
+tools='mke2fs tune2fs'
+case $ostype {
+(DragonFly|*BSD*)
+	;;
+(Darwin)
+	tools="$tools fuse-ext2"
+	;;
+(Linux)
+	;;
+(*)
+	print -u2 Sorry, not ported to the OS "'$ostype'" yet.
 	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 [ -b $1 ];then
-		printf "Using $1 as CF/USB disk for installation\n"
-		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
+	;;
+}
+for tool in $tools; do
+	print -n Checking if $tool is installed...
+	if whence -p $tool >/dev/null; then
+		print " okay"
 	else
-		printf "Sorry $1 is not a block device\n"
-		exit 1
+		print " failed"
+		f=1
 	fi
+done
+(( f )) && exit 1
+
+tgt=$1
+src=$2
+
+if [[ ! -b $tgt ]]; then
+	print -u2 "'$tgt' is not a block device, exiting"
+	exit 1
 fi
-	
-if [ $(mount | grep $1| wc -l) -ne 0 ];then
-	printf "Block device $1 is in use, please umount first.\n"
+if [[ ! -f $src ]]; then
+	print -u2 "'$src' is not a file, exiting"
 	exit 1
 fi
+(( quiet )) || print "Installing $src on $tgt."
 
-case $2 in
-	wrap*)
-		speed=38400
-		;;
-	*)
-		speed=115200
-		;;
-esac
-
-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
-tar -C $tmp -xzpf $2 
-printf "Fixing permissions ...\n"
-chmod 1777 $tmp/tmp
-chmod 4755 $tmp/bin/busybox
-
-printf "Installing GRUB bootloader ...\n"
-mkdir -p $tmp/boot/grub
-cat << EOF > $tmp/boot/grub/grub.cfg
-set default=0
-set timeout=1
-terminal_output console
-terminal_input console
-
-menuentry "GNU/Linux (OpenADK)" {
-	insmod ext2
-	set root=(hd0,1)
-	linux /boot/vmlinuz-adk init=/init
+case $ostype {
+(DragonFly|*BSD*)
+	basedev=${tgt%c}
+	tgt=${basedev}c
+	part=${basedev}i
+	match=\'${basedev}\''[a-p]'
+	function mount_ext2fs {
+		mount -t ext2fs "$1" "$2"
+	}
+	;;
+(Darwin)
+	basedev=$tgt
+	part=${basedev}s1
+	match=\'${basedev}\''?(s+([0-9]))'
+	function mount_ext2fs {
+		fuse-ext2 "$1" "$2" -o force
+		sleep 3
+	}
+	;;
+(Linux)
+	basedev=$tgt
+	part=${basedev}1
+	match=\'${basedev}\''+([0-9])'
+	function mount_ext2fs {
+		mount -t ext2 "$1" "$2"
+	}
+	;;
 }
-EOF
-./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 --modules=ext2 --root-directory=$tmp $1
-umount $tmp
-printf "Successfully installed.\n"
-rm -rf $tmp
+
+mount | while read dev rest; do
+	[[ $dev = $match ]] || continue
+	print -u2 "Block device $tgt is in use, please umount first."
+	exit 1
+done
+
+if (( !quiet )); then
+	print "WARNING: This will overwrite $basedev - type Yes to continue!"
+	read x
+	[[ $x = Yes ]] || exit 0
+fi
+
+dksz=$(dkgetsz "$tgt")
+heads=64
+secs=32
+(( cyls = dksz / heads / secs ))
+if (( cyls < (cfgfs + 2) )); then
+	print -u2 "Size of $tgt is $dksz, this looks fishy?"
+	exit 1
+fi
+
+if stat --help >/dev/null 2>&1; then
+	statcmd='stat -c %s'	# GNU stat
+else
+	statcmd='stat -f %z'	# BSD stat (or so we assume)
+fi
+
+if ! T=$(mktemp -d /tmp/openadk.XXXXXXXXXX); then
+	print -u2 Error creating temporary directory.
+	exit 1
+fi
+"$TOPDIR/scripts/tar" -xOzf "$src" ./usr/share/grub-bin/core.img >"$T/core.img"
+integer coreimgsz=$($statcmd "$T/core.img")
+if (( coreimgsz < 1024 )); then
+	print -u2 core.img is probably too small: $coreimgsz
+	rm -rf "$T"
+	exit 1
+fi
+if (( coreimgsz > 65024 )); then
+	print -u2 core.img is larger than 64K-512: $coreimgsz
+	rm -rf "$T"
+	exit 1
+fi
+(( coreendsec = (coreimgsz + 511) / 512 ))
+# partition offset: at least coreendsec+1 but aligned on a multiple of secs
+(( partofs = ((coreendsec / secs) + 1) * secs ))
+
+(( quiet )) || print Preparing MBR and GRUB2...
+dd if=/dev/zero of="$T/firsttrack" count=$partofs 2>/dev/null
+echo 1 $coreendsec | mksh "$TOPDIR/scripts/bootgrub.mksh" \
+    -A -g $((cyls-cfgfs)):$heads:$secs -M 1:0x83 -O $partofs | \
+    dd of="$T/firsttrack" conv=notrunc 2>/dev/null
+dd if="$T/core.img" of="$T/firsttrack" conv=notrunc seek=1 2>/dev/null
+# set partition where it can find /boot/grub
+print -n '\0\0\0\0' | \
+    dd of="$T/firsttrack" conv=notrunc bs=1 seek=$((0x414)) 2>/dev/null
+
+# create cfgfs partition (mostly taken from bootgrub.mksh)
+set -A thecode
+typeset -Uui8 thecode
+mbrpno=0
+set -A g_code $cyls $heads $secs
+(( psz = g_code[0] * g_code[1] * g_code[2] ))
+(( pofs = (cyls - cfgfs) * g_code[1] * g_code[2] ))
+set -A o_code	# g_code equivalent for partition offset
+(( o_code[2] = pofs % g_code[2] + 1 ))
+(( o_code[1] = pofs / g_code[2] ))
+(( o_code[0] = o_code[1] / g_code[1] + 1 ))
+(( o_code[1] = o_code[1] % g_code[1] + 1 ))
+# boot flag; C/H/S offset
+thecode[mbrpno++]=0x00
+(( thecode[mbrpno++] = o_code[1] - 1 ))
+(( cylno = o_code[0] > 1024 ? 1023 : o_code[0] - 1 ))
+(( thecode[mbrpno++] = o_code[2] | ((cylno & 0x0300) >> 2) ))
+(( thecode[mbrpno++] = cylno & 0x00FF ))
+# partition type; C/H/S end
+(( thecode[mbrpno++] = 0x88 ))
+(( thecode[mbrpno++] = g_code[1] - 1 ))
+(( cylno = g_code[0] > 1024 ? 1023 : g_code[0] - 1 ))
+(( thecode[mbrpno++] = g_code[2] | ((cylno & 0x0300) >> 2) ))
+(( thecode[mbrpno++] = cylno & 0x00FF ))
+# partition offset, size (LBA)
+(( thecode[mbrpno++] = pofs & 0xFF ))
+(( thecode[mbrpno++] = (pofs >> 8) & 0xFF ))
+(( thecode[mbrpno++] = (pofs >> 16) & 0xFF ))
+(( thecode[mbrpno++] = (pofs >> 24) & 0xFF ))
+(( pssz = psz - pofs ))
+(( thecode[mbrpno++] = pssz & 0xFF ))
+(( thecode[mbrpno++] = (pssz >> 8) & 0xFF ))
+(( thecode[mbrpno++] = (pssz >> 16) & 0xFF ))
+(( thecode[mbrpno++] = (pssz >> 24) & 0xFF ))
+# write partition table entry
+ostr=
+curptr=0
+while (( curptr < 16 )); do
+	ostr=$ostr\\0${thecode[curptr++]#8#}
+done
+print -n "$ostr" | \
+    dd of="$T/firsttrack" conv=notrunc bs=1 seek=$((0x1CE)) 2>/dev/null
+
+(( quiet )) || print Writing MBR and GRUB2 to target device...
+dd if="$T/firsttrack" of="$tgt"
+
+(( quiet )) || print "Creating ext2fs on ${part}..."
+q=
+(( quiet )) && q=-q
+mke2fs $q "$part"
+#partuuid=$(tune2fs -l /dev/sd0i | sed -n '/^Filesystem UUID:[	 ]*/s///p')
+
+(( quiet )) || print Extracting installation archive...
+mount_ext2fs "$part" "$T"
+gzip -dc "$src" | (cd "$T"; tar -xpf -)
+cd "$T"
+rnddev=/dev/urandom
+[[ -c /dev/arandom ]] && rnddev=/dev/arandom
+dd if=$rnddev bs=16 count=1 >>etc/.rnd 2>/dev/null
+(( quiet )) || print Fixing up permissions...
+chown 0:0 tmp
+chmod 1777 tmp
+chmod 4755 bin/busybox
+(( quiet )) || print Configuring GRUB2 bootloader...
+mkdir -p boot/grub
+(
+	print set default=0
+	print set timeout=1
+	if (( serial )); then
+		print serial --unit=0 --speed=$speed
+		print terminal_output serial
+		print terminal_input serial
+		consargs="console=ttyS0,$speed console=tty0"
+	else
+		print terminal_output console
+		print terminal_input console
+		consargs="console=tty0"
+	fi
+	print
+	print 'menuentry "GNU/Linux (OpenADK)" {'
+#	print "\tlinux /boot/vmlinuz-adk root=UUID=$partuuid $consargs panic=10"
+	print "\tlinux /boot/vmlinuz-adk $consargs panic=10"
+	print '}'
+) >boot/grub/grub.cfg
+set -A grubfiles
+ngrubfiles=0
+for a in usr/lib/grub/*-pc/{*.mod,efiemu??.o,command.lst,moddep.lst,fs.lst,handler.lst,parttool.lst}; do
+	[[ -e $a ]] && grubfiles[ngrubfiles++]=$a
+done
+cp "${grubfiles[@]}" boot/grub/
+(( quiet )) || print Finishing up...
+cd "$TOPDIR"
+umount "$T"
+
+rm -rf "$T"
 exit 0

+ 1 - 4
tools/adk/Makefile

@@ -12,13 +12,10 @@ ${TOPDIR}/bin/tools/depmaker: $(TOPDIR)/bin/tools
 ${TOPDIR}/bin/tools/pkgrebuild: $(TOPDIR)/bin/tools
 	$(HOSTCC) -o $(TOPDIR)/bin/tools/pkgrebuild pkgrebuild.c strmap.c
 
-${TOPDIR}/bin/tools/pt: $(TOPDIR)/bin/tools
-	$(HOSTCC) -o $(TOPDIR)/bin/tools/pt pt.c
-
 ${TOPDIR}/bin/tools/dkgetsz: ${TOPDIR}/bin/tools
 	${HOSTCC} -O2 -Wall -o $@ dkgetsz.c
 
 install: ${TOPDIR}/bin/tools/depmaker ${TOPDIR}/bin/tools/pkgrebuild \
-	$(TOPDIR)/bin/tools/pt ${TOPDIR}/bin/tools/dkgetsz
+	${TOPDIR}/bin/tools/dkgetsz
 
 include $(TOPDIR)/mk/tools.mk

+ 0 - 243
tools/adk/pt.c

@@ -1,243 +0,0 @@
-/* 
- * 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
-
-/* 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 = start = sect + sectors;
-		sect = round_to_cyl(start + parts[i].size * 2);
-		pte[i].length = 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);
-}