/*
 * 5799-WZQ (C) COPYRIGHT IBM CORPORATION 1986,1987,1988
 * LICENSED MATERIALS - PROPERTY OF IBM
 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
 */

/* $Header:fdisk.c 12.0$ */
/* $ACIS:fdisk.c 12.0$ */
/* $Source: /ibm/acis/usr/sys/standatr/RCS/fdisk.c,v $ */

#ifndef lint
static char    *rcsid = "$Header:fdisk.c 12.0$";
#endif

#ifndef SAUTIL
#include <sys/types.h>
#include <sys/time.h>
#include <ctype.h>
#include <setjmp.h>
#include <machineio/hdconfig.h>
#ifndef STANDALONE
#include <sys/ioctl.h>
#include <machine/dkio.h>
#include "../ca_atr/pcif.h"		/* defined in ../pc_code/cbcb.h */
#endif
#define TRUE 1
#define FALSE 0
#define NULL	0
#endif SAUTIL
#include "../ca_atr/part.h"
#include "err.h"

/*
 *  information used globally
 */

#ifdef STANDALONE
extern struct hdinfo *hdinfo[];	/* defined in ../caio/hdconfig.h */
#endif STANDALONE

int             current_drive;		/* the drive we are working with at present */
int             valid_parts;		/* a dynamic indication of valid parts/drive */
static struct hdinfo   pcinfo;		/* disk geometries */
struct bootrecord bootrecord;		/* the actual boot records - sector(s) 0 */
struct partdata partdata[NP];		/* partition data in presentable form */
struct partdata *partitions[NP];	/* used for sorting partition entries */
int             filed;			/* hard disk file descriptors */
char            blockholder[BLOCK_SIZE];	/* hold the bootblocks */
static int	acisid;		/* our id index (calculated) */

/*
 * macros to pick up cylinder and sector information */
#define GETCYL(cyl,sector)	/* pick up cylinder info */	\
	((cyl) | ((((u_short)sector) << 2) & 0x0300))
#define GETSECT(sector) ((sector) & 0x3F)

#define ACIS43	0xDB		/* our code */

/*
 *  this table defines all known PC family operating systems and their ids
 */

struct system   systems[NSYSTEMS + 1] =
{
 {"DOS       ", 0x01},		/* DOS, 12-bit FAT      */
 {"XENIX root", 0x02},		/* XENIX root (/)       */
 {"XENIX user", 0x03},		/* XENIX user (/usr)    */
 {"DOS       ", 0x04},		/* DOS, 16-bit FAT      */
 {"DOS       ", 0x05},		/* DOS, Extended Part.  */
 {"PC/IX     ", 0x75},		/* PC/IX                */
 {"ACIS 4.3  ", ACIS43},	/* ACIS 4.3             */
 {"UNKNOWN   ", 0x00},		/* Unknown system       */
};

unsigned int    bootrec[128] = {0xfa33c08e, 0xd0bc007c, 0x8bf45007, 0x501ffbfc,
				0xbf0006b9, 0x0001f2a5, 0xea1d0600, 0x00bebe07,
				0xb304803c, 0x80740e80, 0x3c00751c, 0x83c610fe,
				0xcb75efcd, 0x188b148b, 0x4c028bee, 0x83c610fe,
				0xcb741a80, 0x3c0074f4, 0xbe8b06ac, 0x3c00740b,
				0x56bb0700, 0xb40ecd10, 0x5eebf0eb, 0xfebf0500,
				0xbb007cb8, 0x010257cd, 0x135f730c, 0x33c0cd13,
				0x4f75edbe, 0xa306ebd3, 0xbec206bf, 0xfe7d813d,
				0x55aa75c7, 0x8bf5ea00, 0x7c000049, 0x6e76616c,
				0x69642070, 0x61727469, 0x74696f6e, 0x20746162,
				0x6c650045, 0x72726f72, 0x206c6f61, 0x64696e67,
				0x206f7065, 0x72617469, 0x6e672073, 0x79737465,
				0x6d004d69, 0x7373696e, 0x67206f70, 0x65726174,
				0x696e6720, 0x73797374, 0x656d0000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x000055aa,
};



#define vp valid_parts		/* a useful abbreviation */
#define cd current_drive	/* a useful abbreviation */

int vflg;			/* verbose output */
int iflg;			/* automatic initialization */

char *prompt();
char *index();
static char	  *fp;

main(argc, argv)
    int             argc;
    char          **argv;
{
    char           *cmd;
    int		    how;
    char	    name[64];	/* place to copy disk name to */

    vflg = 0;
    iflg = 0;
    bzero((char *)&pcinfo, sizeof pcinfo);
    while (argc > 1 && argv[1][0] == '-') {
	switch(argv[1][1]) {
	case 'i':
		iflg++;
		break;
	case 'v':
		vflg++;
		break;
	case 'c':
		pcinfo.ncpd = atoi(argv[1]+2);	/* cylinders */
		break;
	case 't':
		pcinfo.ntpc = atoi(argv[1]+2);
		break;
	case 's':
		pcinfo.nspt = atoi(argv[1]+2);
		break;
	default:
		err("fdisk: invalid option %s",argv[1]);
	}
	++argv; --argc;
    }
		
    if (argc > 1) {
	cd = getunit(argv[1]);
	fp = argv[1];
    } else {
	printf("Typical disk names are hd(unit,7) where unit=0 or 1\n");
	fp = prompt("disk ");
	strcpy(name, fp);
	fp = name;
	cd = getunit(fp);
    }

    if (getpart(fp) != 7) {
	printf("Disk names must be hd(unit,7) where unit=0 or 1\n");
	exit(1);
    }
    if ((filed = open(fp, how = 2)) < 0 && (filed = open(fp, how = 0)) < 0) {
	printf("can't open %s", fp);
	exit(1);
    }
    if (how == 0)
	printf("%s opened read-only\n",fp);
    fdinitialize(iflg);
    fdprint();

    for (;;) {

	cmd = prompt("> ");

	if (cmd == 0)
	    break;

	if (cmdcmp(cmd, "quit"))
	    break;

	else if (cmdcmp(cmd, "change")) {
	    fdchange();
	    writeblock();
	} else if (cmdcmp(cmd, "create")) {
	    fdcreate();
	    writeblock();
	} else if (cmdcmp(cmd, "initialize")) {
	    if (yes("confirm (all partitions (DOS, Unix, etc) and data will be lost) [y/n] ", 0))
	    	fdinitialize(1);		/* force initialization */
	    else
		printf("cancelled\n");
	    fdprint();
	} else if (cmdcmp(cmd, "delete")) {
	    fddelete();
	    writeblock();
	} else if (cmdcmp(cmd, "list"))
	    fdprint();

	else if (cmdcmp(cmd, "disk")) {
	    close(filed);
	    bzero((char *)&pcinfo, sizeof pcinfo);	/* clear size info */
	    fp = prompt("disk ");
	    strcpy(name, fp);
	    fp = name;
	    cd = getunit(fp);
	    if (getpart(fp) != 7) {
		printf("Disk names must be hd(unit,7) where unit=0 or 1\n");
		exit(1);
	    }
	    if ((filed = open(fp, 2)) < 0 && (filed = open(fp, 0)) < 0) {
		printf("can't open %s", fp);
		exit(1);
	    }
	    fdinitialize(iflg);
	    fdprint();
	    continue;
	} else if (cmdcmp(cmd, "help") || cmdcmp(cmd, "?"))
	    usage();

	else {
	    printf("** Invalid Command **\n");
	    printf("Enter help or ? for valid commands \n");
	}

    }
}

fdchange()
{
    char            choice;
    int             i, valid_choice = 0;
    char           *answer;

    fdprint();

    if (valid_parts) {	/* if in fact there are any defined */
	while (!valid_choice) {
	    answer = prompt("Which Partition number do you wish to make active? ");
	    if (answer == 0 || *answer == 0) {
		printf("Cancelled\n");
		return;
	    }
	    choice = atoi(answer);
	    if ((choice < 0) || (choice >= vp))	/* bounds check response */
		printf("\nInvalid Partition Number. Try Again.");
	    else
		valid_choice = 1;
	}

	if (partitions[choice]->bootable) {	/* already active, just return */
	    printf("partition %d already active\n",choice);
	    return;
	} else
	    for (i = 0; i < NP; i++)
		if (partitions[i])
		    partitions[i]->bootable = (i == choice) ? TRUE : FALSE;

    }
}

fdcreate()
{
    struct hdconfig config;
    int             i, startcyl, partlength;
    int             previousend, validend, validlength;
    struct partdata *tempptr;
    char           *answer, file[20];
    int             valid_choice = 0;
    int		    type = ACIS43;
    int		    relsector;

    fdprint();

    for (i = 0; i < NP; i++)
	if (partdata[i].sysno == acisid) {
	    printf("4.3 Partition Already Defined\n");
	    return (0);
	}
    while (!valid_choice) {
	startcyl = cvtcyl(answer = prompt("Starting Cylinder? "));
	if (answer == 0)
	    return (0);
	if ((startcyl < 0) || (startcyl > pcinfo.ncpd - 1)) {
	    printf("Cylinder Number Out of Range\n");
	    continue;
	}
	for (i = 0; (i < vp) && (startcyl >= partitions[i]->start); i++);

	previousend = ((i == 0) ? -1 : partitions[i - 1]->end);
	if (startcyl <= previousend)
	    printf("%d is within partition %d \n", startcyl, i - 1);
	else
	    valid_choice = 1;
    }

    validend = ((i == vp) ? pcinfo.ncpd - 1 : partitions[i]->start - 1);
    validlength = validend - startcyl + 1;

endagain:
    printf("(%d maximum) ", validlength);
    answer = prompt("Partition Length? ");
    if (answer == 0 || *answer == 0)
	partlength = validlength;	/* use the default */
    else
	partlength = atoi(answer);
    if ((partlength < 1) || (partlength > validlength)) {
	printf("Cylinder Number (%d) Out of Range %d ... %d\n", 1, validlength);
	goto endagain;
    }
    for (i = 0; i < NP && partdata[i].sysind; i++);	/* search for free entry */
    if (i >= NP)
	err("no free partition");	/* there is ALWAYS a free entry but we
					 * check anyway */
    /*
     * if the user answered the number of cylinders and provided a comma
     * and the partition type (in hex) then we use that type.
     */
    if (answer && (answer = index(answer,',')))
	type = atox(answer+1);

    tempptr = partitions[vp] = &partdata[i];

    /*
     * we install 4.3 partitions so that we use the entire cylinder
     * including all of cylinder zero (so that the 4.3 partition starts
     * at the correct spot).
     */
    tempptr->sysind = type;
    tempptr->sysno = getsysno(type);
    tempptr->start = startcyl;
    tempptr->starthead = ((startcyl == 0 && tempptr->sysno == acisid) ? 1 : 0);
    tempptr->startsect = 1;
    tempptr->end = startcyl + partlength - 1;
    tempptr->endhead = pcinfo.ntpc - 1;
    tempptr->endsect = pcinfo.nspt;
    tempptr->relsect = relsector = (startcyl * pcinfo.ntpc * pcinfo.nspt) +
	(tempptr->starthead * pcinfo.nspt) + tempptr->startsect - 1;
    tempptr->numsect = (partlength * pcinfo.ntpc * pcinfo.nspt) -
	(tempptr->starthead * pcinfo.nspt);

    partsort();

#ifdef STANDALONE
    hdinfo[cd]->pstart = (u_short) startcyl;
    hdinfo[cd]->plen = (u_short) partlength;
    hdinfo[cd]->flag = HDINFO_42PART | HDINFO_PRESENT;
#endif STANDALONE

    if (type != ACIS43)
	return(0);

/*
 * DOS thinks we start at head 1 but our partitions really start
 * at head 0, so we fix things up before we write the configuration record
 */
    if (startcyl == 0)
	relsector = 0;		/* undo the fudge factor */
/*
 * build a configuration record
 */
    bzero(&config, sizeof config);

    config.conf_magic = 0xF8E9DACB;
    config.conf_sectorcount = (int) (partlength * pcinfo.ntpc * pcinfo.nspt);
    config.conf_interleave = 1;	/* interleave = 1:1 */
    config.conf_sectsize = 0x02;/* sectors size=512 */
    config.conf_lastcyl = (short) (startcyl + partlength - 1);	/* last data cyl */
    config.conf_lasttrack = (char) (pcinfo.ntpc - 1);	/* last head number */
    config.conf_lastsect = (char) pcinfo.nspt;	/* last sector number */
    config.conf_maxcyl = (short) startcyl + partlength - 1;	/* last physical cyl */

	switch(pcinfo.ntpc) {

			case 4:
					strcpy(config.conf_name, "hdps02");
					break;

			case 5:
					strcpy(config.conf_name, "hdps32");
					break;

			case 7:
					strcpy(config.conf_name, "hdps31");
					break;

			case 64:
					strcpy(config.conf_name, "hdpses");
					break;

			default:
					printf("warning: unknown geometry (%d cyl, %d heads, %d sectors)", config.conf_lastcyl+1, config.conf_lasttrack+1, config.conf_lastsect);
					sprintf(config.conf_name,"hdps%02d", atoi(prompt("enter BIOS type code (0...63) ")));
					break;
			}

    lseek(filed, (relsector + CONFIG_BLOCK) * BLOCK_SIZE, 0);

    if (write(filed, &config, sizeof config) != sizeof config) {
	printf("%s: write error writing config record\n", file);
	return (-1);
    }
    printf("Configuration record written to relative block %d (absolute %d) of %s.\n",
	   CONFIG_BLOCK, relsector + CONFIG_BLOCK,fp);

    return (0);

}


fddelete()
{
    char            choice;
    int             valid_choice = 0;
    char           *answer;
    int		    id;

    fdprint();

    while (!valid_choice) {
	answer = prompt("Which Partition number do you wish to delete? ");
	if (answer == 0 || *answer == 0) {
	    printf("Cancelled\n");
	    return;
	}
	choice = atoi(answer);
	if ((choice < 0) || (choice >= vp))	/* bounds check response */
	    printf("\nInvalid Partition Number. Try Again.");
	else {
	    if ((id = partitions[choice]->sysno) != acisid)
		printf("That is a %s partition - ",systems[id].name);
	    if (yes("Please confirm deletion (yes/no) ", 'n'))
		valid_choice = 1;
	}
    }

    partitions[choice]->sysind = 0;	/* back to the shadows */
    partitions[choice]->sysno = 0;

#ifdef STANDALONE
    hdinfo[cd]->pstart = 0;
    hdinfo[cd]->plen = 0;
    hdinfo[cd]->flag = HDINFO_PRESENT;
#endif STANDALONE


    partsort();			/* let partsort do the work */
}


fdinitialize(flag)
int flag;
{
    int             i;
    char           *cp;


    acisid = getsysno(ACIS43);		/* our id index */
    lseek(filed, 0L, 0);		/* see to start block */
    if ((i = read(filed, blockholder, BLOCK_SIZE)) != BLOCK_SIZE)
	printf("only read %d bytes \n", i);

    bcopy(&blockholder[BRPT_OFFSET], &bootrecord, sizeof(struct bootrecord) - 2);

#define sig(n) bootrecord.signature[n]
    if (flag)
	init_pt();
    else {
	if ((sig(0) != 0x55) || (sig(1) != 0xAA)) {

	printf("HD%d: invalid or no partition table found\n", cd);
	cp = prompt("Do you want to initialize the partition table ?");
	if (cmdcmp(cp, "yes"))
	    init_pt();
	else
	    return;
	}
    }
#ifdef STANDALONE
    if (pcinfo.ncpd == 0)
	pcinfo.ncpd = hdinfo[cd]->ncpd;	/* global disk info at 0x800 */
    if (pcinfo.ntpc == 0)
	pcinfo.ntpc = hdinfo[cd]->ntpc;
    if (pcinfo.nspt == 0)
	pcinfo.nspt = hdinfo[cd]->nspt;
#else
    /*
     * use ioctl to read information from driver 
     */
    if (pcinfo.ncpd == 0 || pcinfo.ntpc == 0 || pcinfo.nspt == 0) {
	struct	dkpart dk;

	if (ioctl(filed, DKIOCGPART, &dk) < 0)
		err("could not read configuration info (DKIOCPART failed)");
	if (pcinfo.ncpd == 0)
	    pcinfo.ncpd = dk.dk_ncyl;
	if (pcinfo.ntpc == 0)
	    pcinfo.ntpc = dk.dk_ntrack;
	if (pcinfo.nspt == 0)
	    pcinfo.nspt = dk.dk_nsector;
    }
#endif STANDALONE
#ifdef DEBUG
    if (vflg)
	printf("ncpd=%d ntpc=%d nspt=%d\n", pcinfo.ncpd, pcinfo.ntpc, pcinfo.nspt);
#endif DEBUG

    decode();			/* convert raw info to presentable form */
    partsort();			/* sort the pointers to the valid partition entries */

}


init_pt()
{				/* init the boot record */
    if (lseek(filed, 0, 0) != 0) {
	printf("HD%d: seek error\n", cd);
	return (-1);
    }
    if (write(filed, bootrec, sizeof(bootrec)) != sizeof(bootrec)) {
	printf("HD%d: write error writing partition table\n", cd);
	return (-1);
    } else {
	bcopy(&bootrec, blockholder, BLOCK_SIZE);
	bcopy(&blockholder[BRPT_OFFSET], &bootrecord, sizeof(struct bootrecord) - 2);
	return (0);		/* boot record written OK */
    }

}

usage()
{
    printf("Valid commands are:\n\n");
    printf("change          change active partition\n");
    printf("create          create a new 4.3 partition\n");
    printf("initialize      initialize partition table\n");
    printf("delete          delete a partition\n");
    printf("list            list partition data\n");
    printf("disk            switch to the other disk\n");
    printf("help            this display of help messages\n");
    printf("quit            leave fdisk program\n");
    printf("\n");
}


partsort()
{				/* sorting entries for the current drive */
    int             i, j, k;
    struct partdata *tempptr;	/* for efficiency */

    vp = 0;			/* reset the number of valid entries */
    for (i = 0; i < NP; i++) {	/* for each partition entry */
	tempptr = &partdata[i];	/* set up the temporary pointer */
	partitions[i] = NULL;	/* clear it out */
	if (tempptr->sysind == 0)/* no partition defined here */
	    continue;		/* try the next entry */
	if (vp == 0)	/* first valid entry encountered */
	    partitions[vp++] = &partdata[i];	/* set pointer to it */
	else {			/* not the first, find out where it should go */
	    for (j = 0; (j < vp && tempptr->end > partitions[j]->end); j++);
	    if (j == vp)	/* this one goes after existing valid entries */
		partitions[vp++] = tempptr;	/* set the pointer */
	    else {		/* have to insert this one at position j */
		for (k = vp++; k > j; k--)	/* starting at end of the valid entries */
		    partitions[k] = partitions[k - 1];	/* shift them down one */
		partitions[j] = tempptr;	/* put it where it belongs */

	    }			/* had to insert */
	}			/* not the first valid entry */
    }				/* for each partition entry */

#ifdef DEBUG
    for (i = vp; i < NP; i++)	/* blank out unused pointers */
	partitions[i] = NULL;
#endif DEBUG
}

writeblock()
{
    int             i;

    encode();

    lseek(filed, (long) BOOTRECORD_BLOCK * BLOCK_SIZE, 0);
    bcopy(&bootrecord, &blockholder[BRPT_OFFSET], sizeof(struct bootrecord) - 2);

    if ((i = write(filed, blockholder, BLOCK_SIZE)) != BLOCK_SIZE)
	printf("only wrote %d bytes \n", i);
}


/*
 * take the partition table as found in the boot record and
 * convert it to a more managable form.
 */
decode()
{
    struct brpt_entry *pentry;
    struct partdata *info;
    int             i;

#ifdef DEBUG
    if (vflg)
	printf("# id boot start	sect	head	end	sect	head	relsect	numsect\n");
#endif DEBUG
    for (i = 0; i < NP; i++) {
	pentry = &bootrecord.t_entry[i];
	info = &partdata[i];

	info->sysind = pentry->sys_ind;
	info->sysno = getsysno(pentry->sys_ind);
	info->bootable = (char) ((pentry->boot_ind == 0x80) ? TRUE : FALSE);
	info->start = GETCYL(pentry->start_cyl, pentry->start_sect);
	info->startsect = GETSECT(pentry->start_sect);
	info->starthead = pentry->start_hd;
	info->end = GETCYL(pentry->end_cyl, pentry->end_sect);
	info->endsect = GETSECT(pentry->end_sect);
	info->endhead = pentry->end_hd;
	info->numsect = SWAPW(pentry->num_sect);
	info->relsect = SWAPW(pentry->rel_sect);
#ifdef DEBUG
	if (vflg)
	    printf("%d %02x  %d	%5d	%5d	%5d	%5d	%5d	%5d	%5d	%5d\n",
	    i, info->sysind, info->bootable != 0 , info->start, info->startsect,
		info->starthead, info->end, info->endsect, info->endhead, info->relsect,
		info->numsect);
#endif DEBUG
    }
}


/*
 * take the information from our internal structure and write it back
 * to the boot record.
 */
encode()
{
    struct partdata *info;
    struct brpt_entry *pentry;
    int             shead, ehead, ssect, esect, i;
    u_short         start, end;

    for (i = 0; i < NP; i++) {
	info = partitions[i];
	pentry = &bootrecord.t_entry[i];

	if (info != NULL) {	/* real data to fill in */
	    start = info->start;
	    end = info->end;
	    shead = info->starthead;
	    ehead = info->endhead;
	    ssect = info->startsect;
	    esect = info->endsect;

	    pentry->sys_ind = info->sysind;
	    pentry->boot_ind = (info->bootable) ? 0x80 : 0;

	    pentry->start_cyl = (char) (start & 0x00FF);
	    pentry->end_cyl = (char) (end & 0x00FF);

	    pentry->start_sect = (char) ((start & 0x0300) >> 2 | ssect);
	    pentry->end_sect = (char) ((end & 0x0300) >> 2 | esect);

	    pentry->start_hd = shead;
	    pentry->end_hd = ehead;

	    pentry->num_sect = SWAPW(info->numsect);

	    pentry->rel_sect = SWAPW(info->relsect);
	} else {		/* just zero out this entry */
	    pentry->sys_ind = 0;
	    pentry->boot_ind = 0;
	    pentry->start_cyl = 0;
	    pentry->end_cyl = 0;
	    pentry->start_sect = 0;
	    pentry->end_sect = 0;
	    pentry->start_hd = 0;
	    pentry->end_hd = 0;
	    pentry->rel_sect = 0;
	    pentry->num_sect = 0;
	}
    }
}


getsysno(id)
    char            id;
{
    int             i;

    for (i = 0; ((i < NSYSTEMS) && (systems[i].id != id)); i++);
    return (i);
}

fdprint()
{
    int             i = -1;

    if (valid_parts == 0)
	printf("No Partitions Defined \n");

    else {
	printf("Partition System      Active  Start  End    Length\n");

	for (i = 0; i < valid_parts; i++) {
	    printf("    %d     ", i);
	    showinfo(partitions[i]);
	}
    }

}

showinfo(info)
    struct partdata *info;
{
    printf("%s  ", systems[info->sysno].name);
    printf("   %s    ", YorN(info->bootable));
    printf("%-6d ", info->start);
    printf("%-6d ", info->end);
    printf("%-6d \n", (info->end >= info->start) ? info->end - info->start + 1 : 0);
}


getpart(fp)
    register char  *fp;
{
    register char  *p = index(fp, 0);
    int             unit = 0;

    while (--p > fp)
#ifdef STANDALONE
	if (isdigit(*p)) {
	    unit = *p - '0';
	    break;
	}
#else
	if ('a' <= *p && *p <= 'h' && isdigit(p[-1])) {
	    unit = *p - 'a';
	    break;
	}
#endif
    return (unit);

}

cvtcyl(str)
char *str;
{
	char *save_str = str;
	int n, factor;
	int cyl = pcinfo.ntpc * pcinfo.nspt;	/* cylinder size */
	int round_n;

	if (str == 0)
		return(0);
	n = atoi(str);
	if (*str == '+' || *str == '-')
		++str;			/* skip sign */
	while (isdigit(*str))
		++str;			/* skip over digits */
	switch(*str)
		{
	default:
		printf("warning: unknown conversion factor %s (not m,k,b,t or c) - assuming cylinders\n", str);
	case 0:
	case 'c':
		factor = cyl;	/* conversion factor is cylinders */
		break;
	case 't':
		factor = pcinfo.nspt;
		break;
	case 'k':
		factor = 2;	/* 2 blocks/k */
		break;
	case 'b':
		factor = 1;	/* in blocks */
		break;
	case 'm':
		factor = 1024 * 2;	/* in megs */
		break;
		}
	n *= factor;
	round_n = (n+cyl-1)/cyl*cyl;
	if (n != round_n)
		printf("%s adjusted to %d (512 byte) blocks (%d cylinders)\n",
			save_str,round_n,round_n/cyl);
			
	return(round_n/cyl);
}
