Home | History | Annotate | Line # | Download | only in fdisk
fdisk.c revision 1.12
      1  1.12  thorpej /*	$NetBSD: fdisk.c,v 1.12 1997/03/29 20:46:17 thorpej Exp $	*/
      2  1.10      cgd 
      3   1.4  mycroft /*
      4   1.1      cgd  * Mach Operating System
      5   1.1      cgd  * Copyright (c) 1992 Carnegie Mellon University
      6   1.1      cgd  * All Rights Reserved.
      7   1.4  mycroft  *
      8   1.1      cgd  * Permission to use, copy, modify and distribute this software and its
      9   1.1      cgd  * documentation is hereby granted, provided that both the copyright
     10   1.1      cgd  * notice and this permission notice appear in all copies of the
     11   1.1      cgd  * software, derivative works or modified versions, and any portions
     12   1.1      cgd  * thereof, and that both notices appear in supporting documentation.
     13   1.4  mycroft  *
     14   1.1      cgd  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
     15   1.1      cgd  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
     16   1.1      cgd  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
     17   1.4  mycroft  *
     18   1.1      cgd  * Carnegie Mellon requests users of this software to return to
     19   1.4  mycroft  *
     20   1.1      cgd  *  Software Distribution Coordinator  or  Software.Distribution (at) CS.CMU.EDU
     21   1.1      cgd  *  School of Computer Science
     22   1.1      cgd  *  Carnegie Mellon University
     23   1.1      cgd  *  Pittsburgh PA 15213-3890
     24   1.4  mycroft  *
     25   1.1      cgd  * any improvements or extensions that they make and grant Carnegie Mellon
     26   1.1      cgd  * the rights to redistribute these changes.
     27   1.1      cgd  */
     28   1.1      cgd 
     29   1.2  mycroft #ifndef lint
     30  1.12  thorpej static char rcsid[] = "$NetBSD: fdisk.c,v 1.12 1997/03/29 20:46:17 thorpej Exp $";
     31   1.2  mycroft #endif /* not lint */
     32   1.2  mycroft 
     33   1.1      cgd #include <sys/types.h>
     34   1.1      cgd #include <sys/disklabel.h>
     35   1.4  mycroft #include <sys/ioctl.h>
     36   1.1      cgd #include <sys/stat.h>
     37   1.4  mycroft 
     38   1.8      cgd #include <ctype.h>
     39   1.4  mycroft #include <err.h>
     40   1.1      cgd #include <fcntl.h>
     41   1.4  mycroft #include <stdio.h>
     42   1.4  mycroft #include <stdlib.h>
     43   1.8      cgd #include <string.h>
     44   1.8      cgd #include <unistd.h>
     45   1.1      cgd 
     46   1.1      cgd #define LBUF 100
     47   1.1      cgd static char lbuf[LBUF];
     48   1.1      cgd 
     49   1.1      cgd /*
     50   1.1      cgd  * 14-Dec-89  Robert Baron (rvb) at Carnegie-Mellon University
     51   1.1      cgd  *	Copyright (c) 1989	Robert. V. Baron
     52   1.1      cgd  *	Created.
     53   1.1      cgd  */
     54   1.1      cgd 
     55   1.1      cgd char *disk = "/dev/rwd0d";
     56   1.1      cgd 
     57   1.1      cgd struct disklabel disklabel;		/* disk parameters */
     58   1.1      cgd 
     59   1.5  mycroft int cylinders, sectors, heads, cylindersectors, disksectors;
     60   1.1      cgd 
     61   1.4  mycroft struct mboot {
     62   1.1      cgd 	unsigned char padding[2]; /* force the longs to be long alligned */
     63   1.1      cgd 	unsigned char bootinst[DOSPARTOFF];
     64   1.1      cgd 	struct	dos_partition parts[4];
     65   1.1      cgd 	unsigned short int	signature;
     66   1.1      cgd };
     67   1.1      cgd struct mboot mboot;
     68   1.1      cgd 
     69   1.1      cgd #define ACTIVE 0x80
     70   1.1      cgd #define BOOT_MAGIC 0xAA55
     71   1.1      cgd 
     72   1.5  mycroft int dos_cylinders;
     73   1.1      cgd int dos_heads;
     74   1.1      cgd int dos_sectors;
     75   1.5  mycroft int dos_cylindersectors;
     76   1.1      cgd 
     77   1.4  mycroft #define DOSSECT(s,c)	(((s) & 0x3f) | (((c) >> 2) & 0xc0))
     78   1.4  mycroft #define DOSCYL(c)	((c) & 0xff)
     79   1.4  mycroft int partition = -1;
     80   1.4  mycroft 
     81   1.4  mycroft int a_flag;		/* set active partition */
     82   1.4  mycroft int i_flag;		/* replace partition data */
     83   1.4  mycroft int u_flag;		/* update partition data */
     84   1.4  mycroft 
     85   1.4  mycroft unsigned char bootcode[] = {
     86   1.4  mycroft 0x33, 0xc0, 0xfa, 0x8e, 0xd0, 0xbc, 0x00, 0x7c, 0x8e, 0xc0, 0x8e, 0xd8, 0xfb, 0x8b, 0xf4, 0xbf,
     87   1.4  mycroft 0x00, 0x06, 0xb9, 0x00, 0x02, 0xfc, 0xf3, 0xa4, 0xea, 0x1d, 0x06, 0x00, 0x00, 0xb0, 0x04, 0xbe,
     88   1.4  mycroft 0xbe, 0x07, 0x80, 0x3c, 0x80, 0x74, 0x0c, 0x83, 0xc6, 0x10, 0xfe, 0xc8, 0x75, 0xf4, 0xbe, 0xbd,
     89   1.4  mycroft 0x06, 0xeb, 0x43, 0x8b, 0xfe, 0x8b, 0x14, 0x8b, 0x4c, 0x02, 0x83, 0xc6, 0x10, 0xfe, 0xc8, 0x74,
     90   1.4  mycroft 0x0a, 0x80, 0x3c, 0x80, 0x75, 0xf4, 0xbe, 0xbd, 0x06, 0xeb, 0x2b, 0xbd, 0x05, 0x00, 0xbb, 0x00,
     91   1.4  mycroft 0x7c, 0xb8, 0x01, 0x02, 0xcd, 0x13, 0x73, 0x0c, 0x33, 0xc0, 0xcd, 0x13, 0x4d, 0x75, 0xef, 0xbe,
     92   1.4  mycroft 0x9e, 0x06, 0xeb, 0x12, 0x81, 0x3e, 0xfe, 0x7d, 0x55, 0xaa, 0x75, 0x07, 0x8b, 0xf7, 0xea, 0x00,
     93   1.4  mycroft 0x7c, 0x00, 0x00, 0xbe, 0x85, 0x06, 0x2e, 0xac, 0x0a, 0xc0, 0x74, 0x06, 0xb4, 0x0e, 0xcd, 0x10,
     94   1.1      cgd 0xeb, 0xf4, 0xfb, 0xeb, 0xfe,
     95   1.1      cgd 'M', 'i', 's', 's', 'i', 'n', 'g', ' ',
     96   1.1      cgd 	'o', 'p', 'e', 'r', 'a', 't', 'i', 'n', 'g', ' ', 's', 'y', 's', 't', 'e', 'm', 0,
     97   1.4  mycroft 'E', 'r', 'r', 'o', 'r', ' ', 'l', 'o', 'a', 'd', 'i', 'n', 'g', ' ',
     98   1.1      cgd 	'o', 'p', 'e', 'r', 'a', 't', 'i', 'n', 'g', ' ', 's', 'y', 's', 't', 'e', 'm', 0,
     99   1.1      cgd 'I', 'n', 'v', 'a', 'l', 'i', 'd', ' ',
    100   1.1      cgd 	'p', 'a', 'r', 't', 'i', 't', 'i', 'o', 'n', ' ', 't', 'a', 'b', 'l', 'e', 0,
    101   1.1      cgd 'A', 'u', 't', 'h', 'o', 'r', ' ', '-', ' ',
    102   1.4  mycroft 	'S', 'i', 'e', 'g', 'm', 'a', 'r', ' ', 'S', 'c', 'h', 'm', 'i', 'd', 't', 0,0,0,
    103   1.1      cgd 
    104   1.4  mycroft   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    105   1.4  mycroft   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    106   1.4  mycroft   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    107   1.4  mycroft   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    108   1.4  mycroft   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    109   1.4  mycroft   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    110   1.4  mycroft   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    111   1.4  mycroft   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    112   1.4  mycroft   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    113   1.4  mycroft   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    114   1.4  mycroft   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    115   1.4  mycroft   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    116   1.4  mycroft   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0
    117   1.1      cgd };
    118   1.1      cgd 
    119   1.4  mycroft struct part_type {
    121   1.4  mycroft 	int type;
    122   1.4  mycroft 	char *name;
    123   1.4  mycroft } part_types[] = {
    124   1.4  mycroft 	{0x00, "unused"},
    125   1.4  mycroft 	{0x01, "Primary DOS with 12 bit FAT"},
    126   1.4  mycroft 	{0x02, "XENIX / filesystem"},
    127   1.4  mycroft 	{0x03, "XENIX /usr filesystem"},
    128   1.4  mycroft 	{0x04, "Primary DOS with 16 bit FAT"},
    129   1.4  mycroft 	{0x05, "Extended DOS"},
    130   1.4  mycroft 	{0x06, "Primary 'big' DOS (> 32MB)"},
    131   1.4  mycroft 	{0x07, "OS/2 HPFS, QNX or Advanced UNIX"},
    132   1.4  mycroft 	{0x08, "AIX filesystem"},
    133   1.4  mycroft 	{0x09, "AIX boot partition or Coherent"},
    134   1.4  mycroft 	{0x0A, "OS/2 Boot Manager or OPUS"},
    135   1.4  mycroft 	{0x10, "OPUS"},
    136   1.4  mycroft 	{0x40, "VENIX 286"},
    137   1.4  mycroft 	{0x50, "DM"},
    138   1.4  mycroft 	{0x51, "DM"},
    139   1.4  mycroft 	{0x52, "CP/M or Microport SysV/AT"},
    140   1.4  mycroft 	{0x56, "GB"},
    141   1.4  mycroft 	{0x61, "Speed"},
    142   1.4  mycroft 	{0x63, "ISC UNIX, other System V/386, GNU HURD or Mach"},
    143   1.4  mycroft 	{0x64, "Novell Netware 2.xx"},
    144   1.4  mycroft 	{0x65, "Novell Netware 3.xx"},
    145   1.4  mycroft 	{0x75, "PCIX"},
    146   1.4  mycroft 	{0x80, "Minix 1.1 ... 1.4a"},
    147   1.9  mycroft 	{0x81, "Minix 1.4b ... 1.5.10"},
    148   1.9  mycroft 	{0x82, "Linux swap"},
    149   1.4  mycroft 	{0x83, "Linux filesystem"},
    150   1.4  mycroft 	{0x93, "Amoeba filesystem"},
    151   1.9  mycroft 	{0x94, "Amoeba bad block table"},
    152   1.4  mycroft 	{0xA5, "NetBSD or 386BSD"},
    153   1.4  mycroft 	{0xB7, "BSDI BSD/386 filesystem"},
    154   1.4  mycroft 	{0xB8, "BSDI BSD/386 swap"},
    155   1.4  mycroft 	{0xDB, "Concurrent CPM or C.DOS or CTOS"},
    156   1.4  mycroft 	{0xE1, "Speed"},
    157   1.4  mycroft 	{0xE3, "Speed"},
    158   1.4  mycroft 	{0xE4, "Speed"},
    159   1.4  mycroft 	{0xF1, "Speed"},
    160   1.4  mycroft 	{0xF2, "DOS 3.3+ Secondary"},
    161   1.4  mycroft 	{0xF4, "Speed"},
    162   1.1      cgd 	{0xFF, "BBT (Bad Blocks Table)"},
    163   1.1      cgd };
    164   1.4  mycroft 
    165   1.4  mycroft void	usage __P((void));
    166   1.4  mycroft void	print_s0 __P((int));
    167   1.4  mycroft void	print_part __P((int));
    168  1.11  ghudson void	init_sector0 __P((int));
    169  1.11  ghudson void	intuit_translated_geometry __P((void));
    170  1.11  ghudson int	try_heads __P((quad_t, quad_t, quad_t, quad_t, quad_t, quad_t, quad_t,
    171  1.11  ghudson 		       quad_t));
    172   1.4  mycroft int	try_sectors __P((quad_t, quad_t, quad_t, quad_t, quad_t));
    173   1.4  mycroft void	change_part __P((int));
    174   1.4  mycroft void	print_params __P((void));
    175   1.4  mycroft void	change_active __P((int));
    176   1.4  mycroft void	get_params_to_use __P((void));
    177   1.4  mycroft void	dos __P((int, unsigned char *, unsigned char *, unsigned char *));
    178   1.4  mycroft int	open_disk __P((int));
    179   1.4  mycroft int	read_disk __P((int, void *));
    180   1.4  mycroft int	write_disk __P((int, void *));
    181   1.4  mycroft int	get_params __P((void));
    182   1.4  mycroft int	read_s0 __P((void));
    183   1.4  mycroft int	write_s0 __P((void));
    184   1.5  mycroft int	yesno __P((char *));
    185   1.4  mycroft void	decimal __P((char *, int *));
    186   1.4  mycroft int	type_match __P((const void *, const void *));
    187   1.1      cgd char	*get_type __P((int));
    188   1.4  mycroft 
    189   1.1      cgd int
    190   1.4  mycroft main(argc, argv)
    191   1.4  mycroft 	int argc;
    192   1.1      cgd 	char *argv[];
    193   1.4  mycroft {
    194   1.4  mycroft 	int ch;
    195   1.1      cgd 	int part;
    196   1.4  mycroft 
    197   1.4  mycroft 	a_flag = i_flag = u_flag = 0;
    198   1.4  mycroft 	while ((ch = getopt(argc, argv, "0123aiu")) != -1)
    199   1.4  mycroft 		switch (ch) {
    200   1.4  mycroft 		case '0':
    201   1.4  mycroft 			partition = 0;
    202   1.4  mycroft 			break;
    203   1.4  mycroft 		case '1':
    204   1.4  mycroft 			partition = 1;
    205   1.4  mycroft 			break;
    206   1.4  mycroft 		case '2':
    207   1.4  mycroft 			partition = 2;
    208   1.4  mycroft 			break;
    209   1.4  mycroft 		case '3':
    210   1.4  mycroft 			partition = 3;
    211   1.4  mycroft 			break;
    212   1.4  mycroft 		case 'a':
    213   1.4  mycroft 			a_flag = 1;
    214   1.4  mycroft 			break;
    215   1.4  mycroft 		case 'i':
    216   1.4  mycroft 			i_flag = 1;
    217   1.4  mycroft 		case 'u':
    218   1.1      cgd 			u_flag = 1;
    219   1.4  mycroft 			break;
    220   1.4  mycroft 		default:
    221   1.1      cgd 			usage();
    222   1.4  mycroft 		}
    223   1.4  mycroft 	argc -= optind;
    224   1.1      cgd 	argv += optind;
    225   1.1      cgd 
    226   1.1      cgd 	if (argc > 0)
    227   1.4  mycroft 		disk = argv[0];
    228   1.4  mycroft 
    229   1.1      cgd 	if (open_disk(a_flag || i_flag || u_flag) < 0)
    230   1.1      cgd 		exit(1);
    231  1.11  ghudson 
    232  1.11  ghudson 	if (read_s0())
    233  1.11  ghudson 		init_sector0(1);
    234  1.11  ghudson 
    235  1.11  ghudson 	intuit_translated_geometry();
    236   1.4  mycroft 
    237   1.4  mycroft 	printf("******* Working on device %s *******\n", disk);
    238   1.1      cgd 	if (u_flag)
    239   1.1      cgd 		get_params_to_use();
    240   1.1      cgd 	else
    241   1.1      cgd 		print_params();
    242   1.1      cgd 
    243   1.1      cgd 	printf("Warning: BIOS sector numbering starts with sector 1\n");
    244   1.4  mycroft 	printf("Information from DOS bootblock is:\n");
    245   1.4  mycroft 	if (partition == -1) {
    246   1.4  mycroft 		for (part = 0; part < NDOSPART; part++)
    247   1.4  mycroft 			change_part(part);
    248   1.1      cgd 	} else
    249   1.1      cgd 		change_part(partition);
    250   1.1      cgd 
    251   1.1      cgd 	if (u_flag || a_flag)
    252   1.1      cgd 		change_active(partition);
    253   1.1      cgd 
    254   1.1      cgd 	if (u_flag || a_flag) {
    255   1.1      cgd 		printf("\nWe haven't changed the partition table yet.  ");
    256   1.1      cgd 		printf("This is your last chance.\n");
    257   1.4  mycroft 		print_s0(-1);
    258   1.1      cgd 		if (yesno("Should we write new partition table?"))
    259   1.1      cgd 			write_s0();
    260   1.1      cgd 	}
    261   1.1      cgd 
    262   1.4  mycroft 	exit(0);
    263   1.1      cgd }
    264   1.4  mycroft 
    265   1.4  mycroft void
    266   1.4  mycroft usage()
    267   1.4  mycroft {
    268   1.4  mycroft 
    269   1.4  mycroft 	(void)fprintf(stderr, "usage: fdisk [-aiu] [-0|-1|-2|-3] [device]\n");
    270   1.1      cgd 	exit(1);
    271   1.1      cgd }
    272   1.4  mycroft 
    273   1.1      cgd void
    274   1.4  mycroft print_s0(which)
    275   1.1      cgd 	int which;
    276   1.4  mycroft {
    277   1.1      cgd 	int part;
    278   1.1      cgd 
    279   1.1      cgd 	print_params();
    280   1.4  mycroft 	printf("Information from DOS bootblock is:\n");
    281   1.4  mycroft 	if (which == -1) {
    282   1.4  mycroft 		for (part = 0; part < NDOSPART; part++)
    283   1.4  mycroft 			printf("%d: ", part), print_part(part);
    284   1.1      cgd 	} else
    285   1.1      cgd 		print_part(which);
    286   1.1      cgd }
    287   1.1      cgd 
    288   1.1      cgd static struct dos_partition mtpart = { 0 };
    289  1.12  thorpej 
    290  1.12  thorpej static inline unsigned short
    291  1.12  thorpej getshort(p)
    292  1.12  thorpej 	void *p;
    293  1.12  thorpej {
    294  1.12  thorpej 	unsigned char *cp = p;
    295  1.12  thorpej 
    296  1.12  thorpej 	return cp[0] | (cp[1] << 8);
    297  1.12  thorpej }
    298  1.12  thorpej 
    299  1.12  thorpej static inline void
    300  1.12  thorpej putshort(p, l)
    301  1.12  thorpej 	void *p;
    302  1.12  thorpej 	unsigned short l;
    303  1.12  thorpej {
    304  1.12  thorpej 	unsigned char *cp = p;
    305  1.12  thorpej 
    306  1.12  thorpej 	*cp++ = l;
    307  1.12  thorpej 	*cp++ = l >> 8;
    308  1.12  thorpej }
    309  1.12  thorpej 
    310  1.12  thorpej static inline unsigned long
    311  1.12  thorpej getlong(p)
    312  1.12  thorpej 	void *p;
    313  1.12  thorpej {
    314  1.12  thorpej 	unsigned char *cp = p;
    315  1.12  thorpej 
    316  1.12  thorpej 	return cp[0] | (cp[1] << 8) | (cp[2] << 16) | (cp[3] << 24);
    317  1.12  thorpej }
    318  1.12  thorpej 
    319  1.12  thorpej static inline void
    320  1.12  thorpej putlong(p, l)
    321  1.12  thorpej 	void *p;
    322  1.12  thorpej 	unsigned long l;
    323  1.12  thorpej {
    324  1.12  thorpej 	unsigned char *cp = p;
    325  1.12  thorpej 
    326  1.12  thorpej 	*cp++ = l;
    327  1.12  thorpej 	*cp++ = l >> 8;
    328  1.12  thorpej 	*cp++ = l >> 16;
    329  1.12  thorpej 	*cp++ = l >> 24;
    330  1.12  thorpej }
    331   1.4  mycroft 
    332   1.4  mycroft void
    333   1.4  mycroft print_part(part)
    334   1.1      cgd 	int part;
    335   1.4  mycroft {
    336   1.1      cgd 	struct dos_partition *partp;
    337   1.4  mycroft 
    338   1.6  mycroft 	partp = &mboot.parts[part];
    339   1.1      cgd 	if (!memcmp(partp, &mtpart, sizeof(struct dos_partition))) {
    340   1.1      cgd 		printf("<UNUSED>\n");
    341   1.1      cgd 		return;
    342   1.5  mycroft 	}
    343   1.4  mycroft 	printf("sysid %d (%s)\n", partp->dp_typ, get_type(partp->dp_typ));
    344  1.12  thorpej 	printf("    start %d, size %d (%d MB), flag %x\n",
    345  1.12  thorpej 	    getlong(&partp->dp_start), getlong(&partp->dp_size),
    346   1.5  mycroft 	    getlong(&partp->dp_size) * 512 / (1024 * 1024), partp->dp_flag);
    347   1.5  mycroft 	printf("\tbeg: cylinder %4d, head %3d, sector %2d\n",
    348   1.5  mycroft 	    DPCYL(partp->dp_scyl, partp->dp_ssect),
    349   1.5  mycroft 	    partp->dp_shd, DPSECT(partp->dp_ssect));
    350   1.5  mycroft 	printf("\tend: cylinder %4d, head %3d, sector %2d\n",
    351   1.5  mycroft 	    DPCYL(partp->dp_ecyl, partp->dp_esect),
    352   1.1      cgd 	    partp->dp_ehd, DPSECT(partp->dp_esect));
    353   1.1      cgd }
    354   1.4  mycroft 
    355   1.1      cgd void
    356   1.4  mycroft init_sector0(start)
    357   1.1      cgd 	int start;
    358   1.4  mycroft {
    359   1.1      cgd 	struct dos_partition *partp;
    360   1.4  mycroft 
    361  1.12  thorpej 	memcpy(mboot.bootinst, bootcode, sizeof(bootcode));
    362   1.1      cgd 	putshort(&mboot.signature, BOOT_MAGIC);
    363   1.4  mycroft 
    364   1.1      cgd 	partp = &mboot.parts[3];
    365   1.1      cgd 	partp->dp_typ = DOSPTYP_386BSD;
    366  1.12  thorpej 	partp->dp_flag = ACTIVE;
    367  1.12  thorpej 	putlong(&partp->dp_start, start);
    368   1.1      cgd 	putlong(&partp->dp_size, disksectors - start);
    369  1.12  thorpej 
    370   1.4  mycroft 	dos(getlong(&partp->dp_start),
    371  1.12  thorpej 	    &partp->dp_scyl, &partp->dp_shd, &partp->dp_ssect);
    372   1.4  mycroft 	dos(getlong(&partp->dp_start) + getlong(&partp->dp_size) - 1,
    373  1.11  ghudson 	    &partp->dp_ecyl, &partp->dp_ehd, &partp->dp_esect);
    374  1.11  ghudson }
    375  1.11  ghudson 
    376  1.11  ghudson /* Prerequisite: the disklabel parameters and master boot record must
    377  1.11  ghudson  *		 have been read (i.e. dos_* and mboot are meaningful).
    378  1.11  ghudson  * Specification: modifies dos_cylinders, dos_heads, dos_sectors, and
    379  1.11  ghudson  *		  dos_cylindersectors to be consistent with what the
    380  1.11  ghudson  *		  partition table is using, if we can find a geometry
    381  1.11  ghudson  *		  which is consistent with all partition table entries.
    382  1.11  ghudson  *		  We may get the number of cylinders slightly wrong (in
    383  1.11  ghudson  *		  the conservative direction).  The idea is to be able
    384  1.11  ghudson  *		  to create a NetBSD partition on a disk we don't know
    385  1.11  ghudson  *		  the translated geometry of.
    386  1.11  ghudson  * This whole routine should be replaced with a kernel interface to get
    387  1.11  ghudson  * the BIOS geometry (which in turn requires modifications to the i386
    388  1.11  ghudson  * boot loader to pass in the BIOS geometry for each disk). */
    389  1.11  ghudson void
    390  1.11  ghudson intuit_translated_geometry()
    391  1.11  ghudson {
    392  1.11  ghudson 	int cylinders = -1, heads = -1, sectors = -1, i, j;
    393  1.11  ghudson 	int c1, h1, s1, c2, h2, s2;
    394  1.11  ghudson 	long a1, a2;
    395  1.11  ghudson 	quad_t num, denom;
    396  1.11  ghudson 
    397  1.11  ghudson 	/* Try to deduce the number of heads from two different mappings. */
    398  1.11  ghudson 	for (i = 0; i < NDOSPART * 2; i++) {
    399  1.11  ghudson 		if (get_mapping(i, &c1, &h1, &s1, &a1) < 0)
    400  1.11  ghudson 			continue;
    401  1.11  ghudson 		for (j = 0; j < 8; j++) {
    402  1.11  ghudson 			if (get_mapping(j, &c2, &h2, &s2, &a2) < 0)
    403  1.11  ghudson 				continue;
    404  1.11  ghudson 			num = (quad_t)h1*(a2-s2) - h2*(a1-s1);
    405  1.11  ghudson 			denom = (quad_t)c2*(a1-s1) - c1*(a2-s2);
    406  1.11  ghudson 			if (denom != 0 && num % denom == 0) {
    407  1.11  ghudson 				heads = num / denom;
    408  1.11  ghudson 				break;
    409  1.11  ghudson 			}
    410  1.11  ghudson 		}
    411  1.11  ghudson 		if (heads != -1)
    412  1.11  ghudson 			break;
    413  1.11  ghudson 	}
    414  1.11  ghudson 
    415  1.11  ghudson 	if (heads == -1)
    416  1.11  ghudson 		return;
    417  1.11  ghudson 
    418  1.11  ghudson 	/* Now figure out the number of sectors from a single mapping. */
    419  1.11  ghudson 	for (i = 0; i < NDOSPART * 2; i++) {
    420  1.11  ghudson 		if (get_mapping(i, &c1, &h1, &s1, &a1) < 0)
    421  1.11  ghudson 			continue;
    422  1.11  ghudson 		num = a1 - s1;
    423  1.11  ghudson 		denom = c1 * heads + h1;
    424  1.11  ghudson 		if (denom != 0 && num % denom == 0) {
    425  1.11  ghudson 			sectors = num / denom;
    426  1.11  ghudson 			break;
    427  1.11  ghudson 		}
    428  1.11  ghudson 	}
    429  1.11  ghudson 
    430  1.11  ghudson 	if (sectors == -1)
    431  1.11  ghudson 		return;
    432  1.11  ghudson 
    433  1.11  ghudson 	/* Estimate the number of cylinders. */
    434  1.11  ghudson 	cylinders = dos_cylinders * dos_cylindersectors / heads / sectors;
    435  1.11  ghudson 
    436  1.11  ghudson 	/* Now verify consistency with each of the partition table entries.
    437  1.11  ghudson 	 * Be willing to shove cylinders up a little bit to make things work,
    438  1.11  ghudson 	 * but translation mismatches are fatal. */
    439  1.11  ghudson 	for (i = 0; i < NDOSPART * 2; i++) {
    440  1.11  ghudson 		if (get_mapping(i, &c1, &h1, &s1, &a1) < 0)
    441  1.11  ghudson 			continue;
    442  1.11  ghudson 		if (sectors * (c1 * heads + h1) + s1 != a1)
    443  1.11  ghudson 			return;
    444  1.11  ghudson 		if (c1 >= cylinders)
    445  1.11  ghudson 			cylinders = c1 + 1;
    446  1.11  ghudson 	}
    447  1.11  ghudson 
    448  1.11  ghudson 	/* Everything checks out.  Reset the geometry to use for further
    449  1.11  ghudson 	 * calculations. */
    450  1.11  ghudson 	dos_cylinders = cylinders;
    451  1.11  ghudson 	dos_heads = heads;
    452  1.11  ghudson 	dos_sectors = sectors;
    453  1.11  ghudson 	dos_cylindersectors = heads * sectors;
    454  1.11  ghudson }
    455  1.11  ghudson 
    456  1.11  ghudson /* For the purposes of intuit_translated_geometry(), treat the partition
    457  1.11  ghudson  * table as a list of eight mapping between (cylinder, head, sector)
    458  1.11  ghudson  * triplets and absolute sectors.  Get the relevant geometry triplet and
    459  1.11  ghudson  * absolute sectors for a given entry, or return -1 if it isn't present.
    460  1.11  ghudson  * Note: for simplicity, the returned sector is 0-based. */
    461  1.11  ghudson int
    462  1.11  ghudson get_mapping(i, cylinder, head, sector, absolute)
    463  1.11  ghudson 	int i, *cylinder, *head, *sector;
    464  1.11  ghudson 	long *absolute;
    465  1.11  ghudson {
    466  1.11  ghudson 	struct dos_partition *part = &mboot.parts[i / 2];
    467  1.11  ghudson 
    468  1.11  ghudson 	if (part->dp_typ == 0)
    469  1.11  ghudson 		return -1;
    470  1.11  ghudson 	if (i % 2 == 0) {
    471  1.11  ghudson 		*cylinder = DPCYL(part->dp_scyl, part->dp_ssect);
    472  1.11  ghudson 		*head = part->dp_shd;
    473  1.12  thorpej 		*sector = DPSECT(part->dp_ssect) - 1;
    474  1.11  ghudson 		*absolute = getlong(&part->dp_start);
    475  1.11  ghudson 	} else {
    476  1.11  ghudson 		*cylinder = DPCYL(part->dp_ecyl, part->dp_esect);
    477  1.11  ghudson 		*head = part->dp_ehd;
    478  1.12  thorpej 		*sector = DPSECT(part->dp_esect) - 1;
    479  1.12  thorpej 		*absolute = getlong(&part->dp_start)
    480  1.11  ghudson 		    + getlong(&part->dp_size) - 1;
    481  1.11  ghudson 	}
    482   1.1      cgd 	return 0;
    483   1.1      cgd }
    484   1.4  mycroft 
    485   1.4  mycroft void
    486   1.4  mycroft change_part(part)
    487   1.1      cgd 	int part;
    488   1.4  mycroft {
    489   1.1      cgd 	struct dos_partition *partp;
    490   1.4  mycroft 
    491   1.1      cgd 	partp = &mboot.parts[part];
    492   1.4  mycroft 
    493   1.4  mycroft 	printf("The data for partition %d is:\n", part);
    494   1.4  mycroft 	print_part(part);
    495   1.4  mycroft 
    496   1.4  mycroft 	if (!u_flag || !yesno("Do you want to change it?"))
    497   1.1      cgd 		return;
    498   1.1      cgd 
    499   1.7  mycroft 	if (i_flag) {
    500   1.4  mycroft 		memset(partp, 0, sizeof(*partp));
    501   1.1      cgd 		if (part == 3) {
    502   1.1      cgd 			init_sector0(1);
    503   1.4  mycroft 			printf("\nThe static data for the DOS partition 3 has been reinitialized to:\n");
    504   1.1      cgd 			print_part(part);
    505   1.1      cgd 		}
    506   1.1      cgd 	}
    507   1.1      cgd 
    508   1.5  mycroft 	do {
    509   1.5  mycroft 		{
    510   1.5  mycroft 			int sysid, start, size;
    511   1.5  mycroft 
    512  1.12  thorpej 			sysid = partp->dp_typ,
    513  1.12  thorpej 			start = getlong(&partp->dp_start),
    514   1.5  mycroft 			size = getlong(&partp->dp_size);
    515   1.5  mycroft 			decimal("sysid", &sysid);
    516   1.5  mycroft 			decimal("start", &start);
    517   1.5  mycroft 			decimal("size", &size);
    518  1.12  thorpej 			partp->dp_typ = sysid;
    519  1.12  thorpej 			putlong(&partp->dp_start, start);
    520   1.5  mycroft 			putlong(&partp->dp_size, size);
    521   1.1      cgd 		}
    522   1.7  mycroft 
    523   1.5  mycroft 		if (yesno("Explicitly specify beg/end address?")) {
    524   1.4  mycroft 			int tsector, tcylinder, thead;
    525   1.5  mycroft 
    526   1.5  mycroft 			tcylinder = DPCYL(partp->dp_scyl, partp->dp_ssect);
    527   1.5  mycroft 			thead = partp->dp_shd;
    528   1.5  mycroft 			tsector = DPSECT(partp->dp_ssect);
    529   1.5  mycroft 			decimal("beginning cylinder", &tcylinder);
    530   1.5  mycroft 			decimal("beginning head", &thead);
    531   1.5  mycroft 			decimal("beginning sector", &tsector);
    532   1.5  mycroft 			partp->dp_scyl = DOSCYL(tcylinder);
    533   1.5  mycroft 			partp->dp_shd = thead;
    534   1.5  mycroft 			partp->dp_ssect = DOSSECT(tsector, tcylinder);
    535   1.5  mycroft 
    536   1.5  mycroft 			tcylinder = DPCYL(partp->dp_ecyl, partp->dp_esect);
    537   1.5  mycroft 			thead = partp->dp_ehd;
    538   1.5  mycroft 			tsector = DPSECT(partp->dp_esect);
    539   1.5  mycroft 			decimal("ending cylinder", &tcylinder);
    540   1.5  mycroft 			decimal("ending head", &thead);
    541   1.5  mycroft 			decimal("ending sector", &tsector);
    542   1.5  mycroft 			partp->dp_ecyl = DOSCYL(tcylinder);
    543   1.5  mycroft 			partp->dp_ehd = thead;
    544   1.1      cgd 			partp->dp_esect = DOSSECT(tsector, tcylinder);
    545  1.12  thorpej 		} else {
    546   1.4  mycroft 			dos(getlong(&partp->dp_start),
    547  1.12  thorpej 			    &partp->dp_scyl, &partp->dp_shd, &partp->dp_ssect);
    548  1.12  thorpej 			dos(getlong(&partp->dp_start)
    549   1.4  mycroft 			    + getlong(&partp->dp_size) - 1,
    550   1.1      cgd 			    &partp->dp_ecyl, &partp->dp_ehd, &partp->dp_esect);
    551   1.4  mycroft 		}
    552   1.4  mycroft 
    553   1.7  mycroft 		print_part(part);
    554   1.1      cgd 	} while (!yesno("Is this entry okay?"));
    555   1.1      cgd }
    556   1.4  mycroft 
    557   1.1      cgd void
    558   1.1      cgd print_params()
    559   1.4  mycroft {
    560   1.1      cgd 
    561   1.5  mycroft 	printf("parameters extracted from in-core disklabel are:\n");
    562   1.5  mycroft 	printf("cylinders=%d heads=%d sectors/track=%d (%d sectors/cylinder)\n\n",
    563   1.5  mycroft 	    cylinders, heads, sectors, cylindersectors);
    564   1.5  mycroft 	if (dos_sectors > 63 || dos_cylinders > 1023 || dos_heads > 255)
    565   1.1      cgd 		printf("Figures below won't work with BIOS for partitions not in cylinder 1\n");
    566   1.5  mycroft 	printf("parameters to be used for BIOS calculations are:\n");
    567   1.5  mycroft 	printf("cylinders=%d heads=%d sectors/track=%d (%d sectors/cylinder)\n\n",
    568   1.1      cgd 	    dos_cylinders, dos_heads, dos_sectors, dos_cylindersectors);
    569   1.1      cgd }
    570   1.4  mycroft 
    571   1.1      cgd void
    572   1.4  mycroft change_active(which)
    573   1.1      cgd 	int which;
    574   1.4  mycroft {
    575   1.4  mycroft 	struct dos_partition *partp;
    576   1.5  mycroft 	int part;
    577   1.4  mycroft 	int active = 3;
    578   1.4  mycroft 
    579   1.1      cgd 	partp = &mboot.parts[0];
    580   1.1      cgd 
    581   1.1      cgd 	if (a_flag && which != -1)
    582   1.4  mycroft 		active = which;
    583   1.4  mycroft 	else {
    584   1.4  mycroft 		for (part = 0; part < NDOSPART; part++)
    585   1.4  mycroft 			if (partp[part].dp_flag & ACTIVE)
    586   1.4  mycroft 				active = part;
    587   1.4  mycroft 	}
    588   1.4  mycroft 	if (yesno("Do you want to change the active partition?")) {
    589   1.5  mycroft 		do {
    590   1.4  mycroft 			decimal("active partition", &active);
    591   1.1      cgd 		} while (!yesno("Are you happy with this choice?"));
    592   1.4  mycroft 	}
    593   1.4  mycroft 	for (part = 0; part < NDOSPART; part++)
    594   1.4  mycroft 		partp[part].dp_flag &= ~ACTIVE;
    595   1.1      cgd 	partp[active].dp_flag |= ACTIVE;
    596   1.1      cgd }
    597   1.4  mycroft 
    598   1.1      cgd void
    599   1.1      cgd get_params_to_use()
    600   1.4  mycroft {
    601   1.1      cgd 
    602   1.4  mycroft 	print_params();
    603   1.4  mycroft 	if (yesno("Do you want to change our idea of what BIOS thinks?")) {
    604   1.5  mycroft 		do {
    605   1.5  mycroft 			decimal("BIOS's idea of #cylinders", &dos_cylinders);
    606   1.5  mycroft 			decimal("BIOS's idea of #heads", &dos_heads);
    607   1.5  mycroft 			decimal("BIOS's idea of #sectors", &dos_sectors);
    608   1.1      cgd 			dos_cylindersectors = dos_heads * dos_sectors;
    609   1.4  mycroft 			print_params();
    610   1.1      cgd 		} while (!yesno("Are you happy with this choice?"));
    611   1.1      cgd 	}
    612   1.1      cgd }
    613   1.1      cgd 
    614   1.1      cgd /***********************************************\
    615   1.1      cgd * Change real numbers into strange dos numbers	*
    616   1.4  mycroft \***********************************************/
    617   1.5  mycroft void
    618   1.5  mycroft dos(sector, cylinderp, headp, sectorp)
    619   1.5  mycroft 	int sector;
    620   1.4  mycroft 	unsigned char *cylinderp, *headp, *sectorp;
    621   1.5  mycroft {
    622   1.4  mycroft 	int cylinder, head;
    623   1.5  mycroft 
    624   1.5  mycroft 	cylinder = sector / dos_cylindersectors;
    625   1.4  mycroft 	sector -= cylinder * dos_cylindersectors;
    626   1.5  mycroft 
    627   1.5  mycroft 	head = sector / dos_sectors;
    628   1.4  mycroft 	sector -= head * dos_sectors;
    629   1.5  mycroft 
    630   1.5  mycroft 	*cylinderp = DOSCYL(cylinder);
    631   1.5  mycroft 	*headp = head;
    632   1.1      cgd 	*sectorp = DOSSECT(sector + 1, cylinder);
    633   1.1      cgd }
    634   1.1      cgd 
    635   1.1      cgd int fd;
    636   1.4  mycroft 
    637   1.1      cgd int
    638   1.4  mycroft open_disk(u_flag)
    639   1.1      cgd 	int u_flag;
    640   1.4  mycroft {
    641   1.1      cgd 	struct stat st;
    642   1.4  mycroft 
    643   1.4  mycroft 	if ((fd = open(disk, u_flag ? O_RDWR : O_RDONLY)) == -1) {
    644   1.4  mycroft 		warn("%s", disk);
    645   1.4  mycroft 		return (-1);
    646   1.4  mycroft 	}
    647   1.4  mycroft 	if (fstat(fd, &st) == -1) {
    648   1.4  mycroft 		close(fd);
    649   1.4  mycroft 		warn("%s", disk);
    650   1.1      cgd 		return (-1);
    651   1.7  mycroft 	}
    652   1.4  mycroft 	if (!S_ISCHR(st.st_mode) && !S_ISREG(st.st_mode)) {
    653   1.7  mycroft 		close(fd);
    654   1.4  mycroft 		warnx("%s is not a character device or regular file", disk);
    655   1.1      cgd 		return (-1);
    656   1.4  mycroft 	}
    657   1.4  mycroft 	if (get_params() == -1) {
    658   1.4  mycroft 		close(fd);
    659   1.1      cgd 		return (-1);
    660   1.4  mycroft 	}
    661   1.1      cgd 	return (0);
    662   1.1      cgd }
    663   1.4  mycroft 
    664   1.1      cgd int
    665   1.4  mycroft read_disk(sector, buf)
    666   1.4  mycroft 	int sector;
    667   1.1      cgd 	void *buf;
    668   1.4  mycroft {
    669   1.4  mycroft 
    670   1.4  mycroft 	if (lseek(fd, (off_t)(sector * 512), 0) == -1)
    671   1.4  mycroft 		return (-1);
    672   1.1      cgd 	return (read(fd, buf, 512));
    673   1.1      cgd }
    674   1.4  mycroft 
    675   1.1      cgd int
    676   1.4  mycroft write_disk(sector, buf)
    677   1.4  mycroft 	int sector;
    678   1.1      cgd 	void *buf;
    679   1.4  mycroft {
    680   1.4  mycroft 
    681   1.4  mycroft 	if (lseek(fd, (off_t)(sector * 512), 0) == -1)
    682   1.4  mycroft 		return (-1);
    683   1.1      cgd 	return (write(fd, buf, 512));
    684   1.1      cgd }
    685   1.4  mycroft 
    686   1.4  mycroft int
    687   1.1      cgd get_params()
    688   1.1      cgd {
    689   1.4  mycroft 
    690   1.4  mycroft 	if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) {
    691   1.4  mycroft 		warn("DIOCGDINFO");
    692   1.4  mycroft 		return (-1);
    693   1.1      cgd 	}
    694   1.5  mycroft 
    695   1.4  mycroft 	dos_cylinders = cylinders = disklabel.d_ncylinders;
    696   1.4  mycroft 	dos_heads = heads = disklabel.d_ntracks;
    697   1.5  mycroft 	dos_sectors = sectors = disklabel.d_nsectors;
    698   1.5  mycroft 	dos_cylindersectors = cylindersectors = heads * sectors;
    699   1.1      cgd 	disksectors = cylinders * heads * sectors;
    700   1.4  mycroft 
    701   1.1      cgd 	return (0);
    702   1.1      cgd }
    703   1.4  mycroft 
    704   1.1      cgd int
    705   1.1      cgd read_s0()
    706   1.4  mycroft {
    707   1.4  mycroft 
    708   1.4  mycroft 	if (read_disk(0, mboot.bootinst) == -1) {
    709   1.4  mycroft 		warn("can't read fdisk partition table");
    710   1.1      cgd 		return (-1);
    711  1.12  thorpej 	}
    712  1.12  thorpej 	if (getshort(&mboot.signature) != BOOT_MAGIC) {
    713   1.4  mycroft 		warnx("invalid fdisk partition table found");
    714   1.4  mycroft 		/* So should we initialize things? */
    715   1.1      cgd 		return (-1);
    716   1.4  mycroft 	}
    717   1.1      cgd 	return (0);
    718   1.1      cgd }
    719   1.4  mycroft 
    720   1.1      cgd int
    721   1.1      cgd write_s0()
    722   1.4  mycroft {
    723   1.4  mycroft 	int flag;
    724   1.1      cgd 
    725   1.1      cgd 	/*
    726   1.1      cgd 	 * write enable label sector before write (if necessary),
    727   1.1      cgd 	 * disable after writing.
    728   1.1      cgd 	 * needed if the disklabel protected area also protects
    729   1.1      cgd 	 * sector 0. (e.g. empty disk)
    730   1.1      cgd 	 */
    731   1.1      cgd 	flag = 1;
    732   1.4  mycroft 	if (ioctl(fd, DIOCWLABEL, &flag) < 0)
    733   1.4  mycroft 		warn("DIOCWLABEL");
    734   1.4  mycroft 	if (write_disk(0, mboot.bootinst) == -1) {
    735   1.1      cgd 		warn("can't write fdisk partition table");
    736   1.4  mycroft 		return -1;
    737   1.1      cgd 	}
    738   1.4  mycroft 	flag = 0;
    739   1.4  mycroft 	if (ioctl(fd, DIOCWLABEL, &flag) < 0)
    740   1.1      cgd 		warn("DIOCWLABEL");
    741   1.1      cgd }
    742   1.4  mycroft 
    743   1.4  mycroft int
    744   1.4  mycroft yesno(str)
    745   1.4  mycroft 	char *str;
    746   1.4  mycroft {
    747   1.1      cgd 	int ch, first;
    748   1.1      cgd 
    749   1.1      cgd 	printf("%s [n] ", str);
    750   1.4  mycroft 
    751   1.4  mycroft 	first = ch = getchar();
    752   1.4  mycroft 	while (ch != '\n' && ch != EOF)
    753   1.4  mycroft 		ch = getchar();
    754   1.1      cgd 	return (first == 'y' || first == 'Y');
    755   1.1      cgd }
    756   1.5  mycroft 
    757   1.5  mycroft void
    758   1.4  mycroft decimal(str, num)
    759   1.5  mycroft 	char *str;
    760   1.1      cgd 	int *num;
    761   1.8      cgd {
    762   1.4  mycroft 	int acc = 0;
    763   1.1      cgd 	char *cp;
    764   1.5  mycroft 
    765   1.5  mycroft 	for (;; printf("%s is not a valid decimal number.\n", lbuf)) {
    766   1.1      cgd 		printf("Supply a decimal value for \"%s\" [%d] ", str, *num);
    767   1.1      cgd 
    768   1.7  mycroft 		fgets(lbuf, LBUF, stdin);
    769   1.7  mycroft 		lbuf[strlen(lbuf)-1] = '\0';
    770   1.7  mycroft 		cp = lbuf;
    771   1.7  mycroft 
    772   1.7  mycroft 		cp += strspn(cp, " \t");
    773   1.5  mycroft 		if (*cp == '\0')
    774   1.1      cgd 			return;
    775   1.7  mycroft 
    776   1.7  mycroft 		if (!isdigit(*cp))
    777   1.5  mycroft 			continue;
    778   1.7  mycroft 		acc = strtol(lbuf, &cp, 10);
    779   1.5  mycroft 
    780   1.5  mycroft 		cp += strspn(cp, " \t");
    781   1.5  mycroft 		if (*cp != '\0')
    782   1.1      cgd 			continue;
    783   1.5  mycroft 
    784   1.5  mycroft 		*num = acc;
    785   1.1      cgd 		return;
    786   1.1      cgd 	}
    787   1.1      cgd 
    788   1.1      cgd }
    789   1.4  mycroft 
    790   1.4  mycroft int
    791   1.4  mycroft type_match(key, item)
    792   1.4  mycroft 	const void *key, *item;
    793   1.4  mycroft {
    794   1.4  mycroft 	const int *typep = key;
    795   1.4  mycroft 	const struct part_type *ptr = item;
    796   1.4  mycroft 
    797   1.4  mycroft 	if (*typep < ptr->type)
    798   1.4  mycroft 		return (-1);
    799   1.4  mycroft 	if (*typep > ptr->type)
    800   1.4  mycroft 		return (1);
    801   1.4  mycroft 	return (0);
    802   1.4  mycroft }
    803   1.4  mycroft 
    804   1.4  mycroft char *
    805   1.4  mycroft get_type(type)
    806   1.4  mycroft 	int type;
    807   1.4  mycroft {
    808   1.4  mycroft 	struct part_type *ptr;
    809   1.4  mycroft 
    810   1.4  mycroft 	ptr = bsearch(&type, part_types,
    811   1.4  mycroft 	    sizeof(part_types) / sizeof(struct part_type),
    812   1.4  mycroft 	    sizeof(struct part_type), type_match);
    813   1.4  mycroft 	if (ptr == 0)
    814   1.4  mycroft 		return ("unknown");
    815   1.4  mycroft 	else
    816   1.1      cgd 		return (ptr->name);
    817                }
    818