fdisk.c revision 4
1/*
2 * Mach Operating System
3 * Copyright (c) 1992 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
19 *  School of Computer Science
20 *  Carnegie Mellon University
21 *  Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie Mellon
24 * the rights to redistribute these changes.
25 */
26
27#include <sys/types.h>
28#include <sys/disklabel.h>
29#include <stdio.h>
30#include <sys/stat.h>
31#include <sys/ioctl.h>
32#include <fcntl.h>
33
34int iotest;
35
36#define LBUF 100
37static char lbuf[LBUF];
38
39/*
40 *
41 * Ported to 386bsd by Julian Elischer  Thu Oct 15 20:26:46 PDT 1992
42 *
43 * 14-Dec-89  Robert Baron (rvb) at Carnegie-Mellon University
44 *	Copyright (c) 1989	Robert. V. Baron
45 *	Created.
46 */
47
48#define Decimal(str, ans, tmp) if (decimal(str, &tmp, ans)) ans = tmp
49#define Hex(str, ans, tmp) if (hex(str, &tmp, ans)) ans = tmp
50#define String(str, ans, len) {char *z = ans; char **dflt = &z; if (string(str, dflt)) strncpy(ans, *dflt, len); }
51
52#define RoundCyl(x) ((((x) + cylsecs - 1) / cylsecs) * cylsecs)
53
54#define SECSIZE 512
55
56char *disk = "/dev/rwd0d";
57char *name;
58
59struct disklabel disklabel;		/* disk parameters */
60
61int cyls, sectors, heads, cylsecs, disksecs;
62
63struct mboot
64{
65	unsigned char padding[2]; /* force the longs to be long alligned */
66	unsigned char bootinst[DOSPARTOFF];
67	struct	dos_partition parts[4];
68	unsigned short int	signature;
69};
70struct mboot mboot;
71
72#define ACTIVE 0x80
73#define BOOT_MAGIC 0xAA55
74
75int dos_cyls;
76int dos_heads;
77int dos_sectors;
78int dos_cylsecs;
79
80#define DOSSECT(s,c) ((s & 0x3f) | ((c >> 2) & 0xc0))
81#define DOSCYL(c)	(c & 0xff)
82static int dos();
83char *get_type();
84static int partition = -1;
85
86
87static int a_flag  = 0;		/* set active partition */
88static int i_flag  = 0;		/* replace partition data */
89static int u_flag  = 0;		/* update partition data */
90
91static unsigned char bootcode[] = {
920x33, 0xc0, 0xfa, 0x8e, 0xd0, 0xbc, 0x00, 0x7c, 0x8e, 0xc0, 0x8e, 0xd8, 0xfb, 0x8b, 0xf4, 0xbf,
930x00, 0x06, 0xb9, 0x00, 0x02, 0xfc, 0xf3, 0xa4, 0xea, 0x1d, 0x06, 0x00, 0x00, 0xb0, 0x04, 0xbe,
940xbe, 0x07, 0x80, 0x3c, 0x80, 0x74, 0x0c, 0x83, 0xc6, 0x10, 0xfe, 0xc8, 0x75, 0xf4, 0xbe, 0xbd,
950x06, 0xeb, 0x43, 0x8b, 0xfe, 0x8b, 0x14, 0x8b, 0x4c, 0x02, 0x83, 0xc6, 0x10, 0xfe, 0xc8, 0x74,
960x0a, 0x80, 0x3c, 0x80, 0x75, 0xf4, 0xbe, 0xbd, 0x06, 0xeb, 0x2b, 0xbd, 0x05, 0x00, 0xbb, 0x00,
970x7c, 0xb8, 0x01, 0x02, 0xcd, 0x13, 0x73, 0x0c, 0x33, 0xc0, 0xcd, 0x13, 0x4d, 0x75, 0xef, 0xbe,
980x9e, 0x06, 0xeb, 0x12, 0x81, 0x3e, 0xfe, 0x7d, 0x55, 0xaa, 0x75, 0x07, 0x8b, 0xf7, 0xea, 0x00,
990x7c, 0x00, 0x00, 0xbe, 0x85, 0x06, 0x2e, 0xac, 0x0a, 0xc0, 0x74, 0x06, 0xb4, 0x0e, 0xcd, 0x10,
1000xeb, 0xf4, 0xfb, 0xeb, 0xfe,
101'M', 'i', 's', 's', 'i', 'n', 'g', ' ',
102	'o', 'p', 'e', 'r', 'a', 't', 'i', 'n', 'g', ' ', 's', 'y', 's', 't', 'e', 'm', 0,
103'E', 'r', 'r', 'o', 'r', ' ', 'l', 'o', 'a', 'd', 'i', 'n', 'g', ' ',
104	'o', 'p', 'e', 'r', 'a', 't', 'i', 'n', 'g', ' ', 's', 'y', 's', 't', 'e', 'm', 0,
105'I', 'n', 'v', 'a', 'l', 'i', 'd', ' ',
106	'p', 'a', 'r', 't', 'i', 't', 'i', 'o', 'n', ' ', 't', 'a', 'b', 'l', 'e', 0,
107'A', 'u', 't', 'h', 'o', 'r', ' ', '-', ' ',
108	'S', 'i', 'e', 'g', 'm', 'a', 'r', ' ', 'S', 'c', 'h', 'm', 'i', 'd', 't', 0,0,0,
109
110  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
111  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
112  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
113  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
114  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
115  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
116  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
117  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
118  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
119  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
120  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
121  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
122  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0
123};
124
125struct part_type
126{
127 unsigned char type;
128 char *name;
129}part_types[] =
130{
131	 {0x00, "unused"}
132	,{0x01, "Primary DOS with 12 bit FAT"}
133	,{0x02, "XENIX / filesystem"}
134	,{0x03, "XENIX /usr filesystem"}
135	,{0x04, "Primary DOS with 16 bit FAT"}
136	,{0x05, "Extended DOS"}
137	,{0x06, "Primary 'big' DOS (> 32MB)"}
138	,{0x07, "OS/2 HPFS, QNX or Advanced UNIX"}
139	,{0x08, "AIX filesystem"}
140	,{0x09, "AIX boot partition or Coherent"}
141	,{0x0A, "OS/2 Boot Manager or OPUS"}
142	,{0x10, "OPUS"}
143	,{0x40, "VENIX 286"}
144	,{0x50, "DM"}
145	,{0x51, "DM"}
146	,{0x52, "CP/M or Microport SysV/AT"}
147	,{0x56, "GB"}
148	,{0x61, "Speed"}
149	,{0x63, "ISC UNIX, other System V/386, GNU HURD or Mach"}
150	,{0x64, "Novell Netware 2.xx"}
151	,{0x65, "Novell Netware 3.xx"}
152	,{0x75, "PCIX"}
153	,{0x80, "Minix 1.1 ... 1.4a"}
154	,{0x81, "Minix 1.4b ... 1.5.10"}
155	,{0x82, "Linux"}
156	,{0x93, "Amoeba filesystem"}
157	,{0x94, "Amoeba bad block table"}
158	,{0xA5, "386BSD"}
159	,{0xB7, "BSDI BSD/386 filesystem"}
160	,{0xB8, "BSDI BSD/386 swap"}
161	,{0xDB, "Concurrent CPM or C.DOS or CTOS"}
162	,{0xE1, "Speed"}
163	,{0xE3, "Speed"}
164	,{0xE4, "Speed"}
165	,{0xF1, "Speed"}
166	,{0xF2, "DOS 3.3+ Secondary"}
167	,{0xF4, "Speed"}
168	,{0xFF, "BBT (Bad Blocks Table)"}
169};
170
171
172main(argc, argv)
173char **argv;
174{
175int	i;
176
177	name = *argv;
178	{register char *cp = name;
179		while (*cp) if (*cp++ == '/') name = cp;
180	}
181
182	for ( argv++ ; --argc ; argv++ ) { register char *token = *argv;
183		if (*token++ != '-' || !*token)
184			break;
185		else { register int flag;
186			for ( ; flag = *token++ ; ) {
187				switch (flag) {
188				case '0':
189					partition = 0;
190					break;
191				case '1':
192					partition = 1;
193					break;
194				case '2':
195					partition = 2;
196					break;
197				case '3':
198					partition = 3;
199					break;
200				case 'a':
201					a_flag = 1;
202					break;
203				case 'i':
204					i_flag = 1;
205				case 'u':
206					u_flag = 1;
207					break;
208				default:
209					goto usage;
210				}
211			}
212		}
213	}
214
215	if (argc > 0)
216		disk = argv[0];
217
218	if (open_disk(u_flag) < 0)
219		exit(1);
220
221	printf("******* Working on device %s *******\n",disk);
222	if(u_flag)
223	{
224		get_params_to_use();
225	}
226	else
227	{
228		print_params();
229	}
230
231	if (read_s0())
232		init_sector0(1);
233
234	printf("Warning: BIOS sector numbering starts with sector 1\n");
235	printf("Information from DOS bootblock is:\n");
236	if (partition == -1)
237		for (i = 0; i < NDOSPART; i++)
238			change_part(i);
239	else
240		change_part(partition);
241
242	if (u_flag || a_flag)
243		change_active(partition);
244
245	if (u_flag || a_flag) {
246		printf("\nWe haven't changed the partition table yet.  ");
247		printf("This is your last chance.\n");
248		print_s0(-1);
249		if (ok("Should we write new partition table?"))
250			write_s0();
251	}
252
253	exit(0);
254
255usage:
256	printf("fdisk {-a|-i|-r} {disk}\n");
257}
258
259print_s0(which)
260{
261int	i;
262
263	print_params();
264	printf("Information from DOS bootblock is:\n");
265	if (which == -1)
266		for (i = 0; i < NDOSPART; i++)
267			printf("%d: ", i), print_part(i);
268	else
269		print_part(which);
270}
271
272static struct dos_partition mtpart = { 0 };
273
274print_part(i)
275{
276struct dos_partition *partp = ((struct dos_partition *) &mboot.parts) + i;
277
278
279	if (!bcmp(partp, &mtpart, sizeof (struct dos_partition))) {
280		printf("<UNUSED>\n");
281		return;
282	}
283	printf("sysid %d,(%s)\n", partp->dp_typ, get_type(partp->dp_typ));
284	printf("    start %d, size %d (%d Meg), flag %x\n",
285		partp->dp_start,
286		partp->dp_size, partp->dp_size * 512 / (1024 * 1024),
287		partp->dp_flag);
288	printf("\tbeg: cyl %d/ sector %d/ head %d;\n\tend: cyl %d/ sector %d/ head %d\n"
289		,DPCYL(partp->dp_scyl, partp->dp_ssect)
290		,DPSECT(partp->dp_ssect)
291		,partp->dp_shd
292		,DPCYL(partp->dp_ecyl, partp->dp_esect)
293		,DPSECT(partp->dp_esect)
294		,partp->dp_ehd);
295}
296
297init_sector0(start)
298{
299struct dos_partition *partp = (struct dos_partition *) (&mboot.parts[3]);
300int size = disksecs - start;
301int rest;
302
303	memcpy(mboot.bootinst, bootcode, sizeof(bootcode));
304	mboot.signature = BOOT_MAGIC;
305
306	partp->dp_typ = DOSPTYP_386BSD;
307	partp->dp_flag = ACTIVE;
308	partp->dp_start = start;
309	partp->dp_size = size;
310
311	dos(partp->dp_start, &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd);
312	dos(partp->dp_start+partp->dp_size, &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd);
313}
314
315change_part(i)
316{
317struct dos_partition *partp = ((struct dos_partition *) &mboot.parts) + i;
318
319    printf("The data for partition %d is:\n", i);
320    print_part(i);
321
322    if (u_flag && ok("Do you want to change it?")) {
323	int tmp;
324
325	if (i_flag) {
326		bzero((char *)partp, sizeof (struct dos_partition));
327		if (i == 3) {
328			init_sector0(1);
329			printf("\nThe static data for the DOS partition 3 has been reinitialized to:\n");
330			print_part(i);
331		}
332	}
333
334	do {
335		Decimal("sysid", partp->dp_typ, tmp);
336		Decimal("start", partp->dp_start, tmp);
337		Decimal("size", partp->dp_size, tmp);
338
339		if (ok("Explicitly specifiy beg/end address ?"))
340		{
341			int	tsec,tcyl,thd;
342			tcyl = DPCYL(partp->dp_scyl,partp->dp_ssect);
343			thd = partp->dp_shd;
344			tsec = DPSECT(partp->dp_ssect);
345			Decimal("beginning cylinder", tcyl, tmp);
346			Decimal("beginning head", thd, tmp);
347			Decimal("beginning sector", tsec, tmp);
348			partp->dp_scyl = DOSCYL(tcyl);
349			partp->dp_ssect = DOSSECT(tsec,tcyl);
350			partp->dp_shd = thd;
351
352			tcyl = DPCYL(partp->dp_ecyl,partp->dp_esect);
353			thd = partp->dp_ehd;
354			tsec = DPSECT(partp->dp_esect);
355			Decimal("ending cylinder", tcyl, tmp);
356			Decimal("ending head", thd, tmp);
357			Decimal("ending sector", tsec, tmp);
358			partp->dp_ecyl = DOSCYL(tcyl);
359			partp->dp_esect = DOSSECT(tsec,tcyl);
360			partp->dp_ehd = thd;
361		} else {
362			dos(partp->dp_start,
363				&partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd);
364			dos(partp->dp_start+partp->dp_size - 1,
365				&partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd);
366		}
367
368		print_part(i);
369	} while (!ok("Are we happy with this entry?"));
370    }
371}
372
373print_params()
374{
375	printf("parameters extracted from in-core disklabel are:\n");
376	printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n"
377			,cyls,heads,sectors,cylsecs);
378	if((dos_sectors > 63) || (dos_cyls > 1023) || (dos_heads > 255))
379		printf(" Figures below won't work with BIOS for partitions not in cyl 1\n");
380	printf("parameters to be used for BIOS calculations are:\n");
381	printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n"
382		,dos_cyls,dos_heads,dos_sectors,dos_cylsecs);
383}
384
385change_active(which)
386{
387int i;
388int active = 3, tmp;
389struct dos_partition *partp = ((struct dos_partition *) &mboot.parts);
390
391	if (a_flag && which != -1)
392		active = which;
393	if (ok("Do you want to change the active partition?")) {
394		do
395			Decimal("active partition", active, tmp);
396		while(!ok("Are you happy with this choice"));
397	}
398	for (i = 0; i < NDOSPART; i++)
399		partp[i].dp_flag = 0;
400	partp[active].dp_flag = ACTIVE;
401}
402
403get_params_to_use()
404{
405	int	tmp;
406	print_params();
407	if (ok("Do you want to change our idea of what BIOS thinks ?"))
408	{
409		do
410		{
411			Decimal("BIOS's idea of #cylinders", dos_cyls, tmp);
412			Decimal("BIOS's idea of #heads", dos_heads, tmp);
413			Decimal("BIOS's idea of #sectors", dos_sectors, tmp);
414			dos_cylsecs = dos_heads * dos_sectors;
415			print_params();
416		}
417		while(!ok("Are you happy with this choice"));
418	}
419}
420
421/***********************************************\
422* Change real numbers into strange dos numbers	*
423\***********************************************/
424static
425dos(sec, c, s, h)
426int sec;
427unsigned char *c, *s, *h;
428{
429int cy;
430int hd;
431
432	cy = sec / ( dos_cylsecs );
433	sec = sec - cy * ( dos_cylsecs );
434
435	hd = sec / dos_sectors;
436	sec = (sec - hd * dos_sectors) + 1;
437
438	*h = hd;
439	*c = cy & 0xff;
440	*s = (sec & 0x3f) | ( (cy & 0x300) >> 2);
441}
442
443int fd;
444
445	/* Getting device status */
446
447open_disk(u_flag)
448{
449struct stat 	st;
450
451	if (stat(disk, &st) == -1) {
452		fprintf(stderr, "%s: Can't get file status of %s\n",
453			name, disk);
454		return -1;
455	} else if ( !(st.st_mode & S_IFCHR) ) {
456		fprintf(stderr,"%s: Device %s is not character special\n",
457			name, disk);
458		return -1;
459	}
460	if ((fd = open(disk, u_flag?O_RDWR:O_RDONLY)) == -1) {
461		fprintf(stderr,"%s: Can't open device %s\n", name, disk);
462		return -1;
463	}
464	if (get_params(0) == -1) {
465		fprintf(stderr, "%s: Can't get disk parameters on %s\n",
466			name, disk);
467		return -1;
468	}
469	return fd;
470}
471
472
473read_disk(sector, buf)
474{
475	lseek(fd,(sector * 512), 0);
476	return read(fd, buf, 512);
477}
478
479write_disk(sector, buf)
480{
481	lseek(fd,(sector * 512), 0);
482	return write(fd, buf, 512);
483}
484
485get_params(verbose)
486{
487
488    if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) {
489	return -1;
490    }
491
492    dos_cyls = cyls = disklabel.d_ncylinders;
493    dos_heads = heads = disklabel.d_ntracks;
494    dos_sectors = sectors = disklabel.d_nsectors;
495    dos_cylsecs = cylsecs = heads * sectors;
496    disksecs = cyls * heads * sectors;
497
498    return (disksecs);
499}
500
501
502read_s0()
503{
504	if (read_disk(0, (char *) mboot.bootinst) == -1) {
505		fprintf(stderr, "%s: Can't read fdisk partition table\n", name);
506		return -1;
507	}
508	if (mboot.signature != BOOT_MAGIC) {
509		fprintf(stderr, "%s: Invalid fdisk partition table found\n",
510			name);
511		/* So should we initialize things */
512		return -1;
513	}
514	return 0;
515}
516
517write_s0()
518{
519	int	flag;
520	if (iotest) {
521		print_s0(-1);
522		return 0;
523	}
524	/*
525	 * write enable label sector before write (if necessary),
526	 * disable after writing.
527	 * needed if the disklabel protected area also protects
528	 * sector 0. (e.g. empty disk)
529	 */
530	flag = 1;
531	if (ioctl(fd, DIOCWLABEL, &flag) < 0)
532		perror("ioctl DIOCWLABEL");
533	if (write_disk(0, (char *) mboot.bootinst) == -1) {
534		fprintf(stderr, "%s: Can't write fdisk partition table\n",
535			name);
536		return -1;
537	flag = 0;
538	(void) ioctl(fd, DIOCWLABEL, &flag);
539	}
540}
541
542
543
544ok(str)
545char *str;
546{
547	printf("%s [n] ", str);
548	fgets(lbuf, LBUF, stdin);
549	lbuf[strlen(lbuf)-1] = 0;
550
551	if (*lbuf &&
552		(!strcmp(lbuf, "yes") || !strcmp(lbuf, "YES") ||
553		 !strcmp(lbuf, "y") || !strcmp(lbuf, "Y")))
554		return 1;
555	else
556		return 0;
557}
558
559decimal(str, num, deflt)
560char *str;
561int *num;
562{
563int acc = 0, c;
564char *cp;
565
566	while (1) {
567		printf("Supply a decimal value for \"%s\" [%d] ", str, deflt);
568		fgets(lbuf, LBUF, stdin);
569		lbuf[strlen(lbuf)-1] = 0;
570
571		if (!*lbuf)
572			return 0;
573
574		cp = lbuf;
575		while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
576		if (!c)
577			return 0;
578		while (c = *cp++) {
579			if (c <= '9' && c >= '0')
580				acc = acc * 10 + c - '0';
581			else
582				break;
583		}
584		if (c == ' ' || c == '\t')
585			while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
586		if (!c) {
587			*num = acc;
588			return 1;
589		} else
590			printf("%s is an invalid decimal number.  Try again\n",
591				lbuf);
592	}
593
594}
595
596hex(str, num, deflt)
597char *str;
598int *num;
599{
600int acc = 0, c;
601char *cp;
602
603	while (1) {
604		printf("Supply a hex value for \"%s\" [%x] ", str, deflt);
605		fgets(lbuf, LBUF, stdin);
606		lbuf[strlen(lbuf)-1] = 0;
607
608		if (!*lbuf)
609			return 0;
610
611		cp = lbuf;
612		while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
613		if (!c)
614			return 0;
615		while (c = *cp++) {
616			if (c <= '9' && c >= '0')
617				acc = (acc << 4) + c - '0';
618			else if (c <= 'f' && c >= 'a')
619				acc = (acc << 4) + c - 'a' + 10;
620			else if (c <= 'F' && c >= 'A')
621				acc = (acc << 4) + c - 'A' + 10;
622			else
623				break;
624		}
625		if (c == ' ' || c == '\t')
626			while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
627		if (!c) {
628			*num = acc;
629			return 1;
630		} else
631			printf("%s is an invalid hex number.  Try again\n",
632				lbuf);
633	}
634
635}
636
637string(str, ans)
638char *str;
639char **ans;
640{
641int c;
642char *cp = lbuf;
643
644	while (1) {
645		printf("Supply a string value for \"%s\" [%s] ", str, *ans);
646		fgets(lbuf, LBUF, stdin);
647		lbuf[strlen(lbuf)-1] = 0;
648
649		if (!*lbuf)
650			return 0;
651
652		while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
653		if (c == '"') {
654			c = *++cp;
655			*ans = cp;
656			while ((c = *cp) && c != '"') cp++;
657		} else {
658			*ans = cp;
659			while ((c = *cp) && c != ' ' && c != '\t') cp++;
660		}
661
662		if (c)
663			*cp = 0;
664		return 1;
665	}
666}
667
668char *get_type(type)
669int	type;
670{
671	int	numentries = (sizeof(part_types)/sizeof(struct part_type));
672	int	counter = 0;
673	struct	part_type *ptr = part_types;
674
675
676	while(counter < numentries)
677	{
678		if(ptr->type == type)
679		{
680			return(ptr->name);
681		}
682		ptr++;
683		counter++;
684	}
685	return("unknown");
686}
687