]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/i386/fdisk/fdisk.c
This is the Linux generic soundcard driver, version 1.0c. Supports
[FreeBSD/FreeBSD.git] / sbin / i386 / fdisk / fdisk.c
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
34 int iotest;
35
36 #define LBUF 100
37 static 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
56 char *disk = "/dev/rwd0d";
57 char *name;
58
59 struct disklabel disklabel;             /* disk parameters */
60
61 int cyls, sectors, heads, cylsecs, disksecs;
62
63 struct 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 };
70 struct mboot mboot;
71
72 #define ACTIVE 0x80
73 #define BOOT_MAGIC 0xAA55
74
75 int dos_cyls;
76 int dos_heads;
77 int dos_sectors;
78 int dos_cylsecs;
79
80 #define DOSSECT(s,c) ((s & 0x3f) | ((c >> 2) & 0xc0))
81 #define DOSCYL(c)       (c & 0xff)
82 static int dos();
83 char *get_type();
84 static int partition = -1;
85
86
87 static int a_flag  = 0;         /* set active partition */
88 static int i_flag  = 0;         /* replace partition data */
89 static int u_flag  = 0;         /* update partition data */
90
91 static unsigned char bootcode[] = {
92 0x33, 0xc0, 0xfa, 0x8e, 0xd0, 0xbc, 0x00, 0x7c, 0x8e, 0xc0, 0x8e, 0xd8, 0xfb, 0x8b, 0xf4, 0xbf, 
93 0x00, 0x06, 0xb9, 0x00, 0x02, 0xfc, 0xf3, 0xa4, 0xea, 0x1d, 0x06, 0x00, 0x00, 0xb0, 0x04, 0xbe, 
94 0xbe, 0x07, 0x80, 0x3c, 0x80, 0x74, 0x0c, 0x83, 0xc6, 0x10, 0xfe, 0xc8, 0x75, 0xf4, 0xbe, 0xbd, 
95 0x06, 0xeb, 0x43, 0x8b, 0xfe, 0x8b, 0x14, 0x8b, 0x4c, 0x02, 0x83, 0xc6, 0x10, 0xfe, 0xc8, 0x74, 
96 0x0a, 0x80, 0x3c, 0x80, 0x75, 0xf4, 0xbe, 0xbd, 0x06, 0xeb, 0x2b, 0xbd, 0x05, 0x00, 0xbb, 0x00, 
97 0x7c, 0xb8, 0x01, 0x02, 0xcd, 0x13, 0x73, 0x0c, 0x33, 0xc0, 0xcd, 0x13, 0x4d, 0x75, 0xef, 0xbe, 
98 0x9e, 0x06, 0xeb, 0x12, 0x81, 0x3e, 0xfe, 0x7d, 0x55, 0xaa, 0x75, 0x07, 0x8b, 0xf7, 0xea, 0x00, 
99 0x7c, 0x00, 0x00, 0xbe, 0x85, 0x06, 0x2e, 0xac, 0x0a, 0xc0, 0x74, 0x06, 0xb4, 0x0e, 0xcd, 0x10, 
100 0xeb, 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 \f
125 struct 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
172 main(argc, argv)
173 char **argv;
174 {
175 int     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
255 usage:
256         printf("fdisk {-a|-i|-r} {disk}\n");
257 }
258
259 print_s0(which)
260 {
261 int     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
272 static struct dos_partition mtpart = { 0 };
273
274 print_part(i)
275 {
276 struct 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
297 init_sector0(start)
298 {
299 struct dos_partition *partp = (struct dos_partition *) (&mboot.parts[3]);
300 int size = disksecs - start;
301 int 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
315 change_part(i)
316 {
317 struct 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
373 print_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
385 change_active(which)
386 {
387 int i;
388 int active = 3, tmp;
389 struct 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
403 get_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 \***********************************************/
424 static
425 dos(sec, c, s, h)
426 int sec;
427 unsigned char *c, *s, *h;
428 {
429 int cy;
430 int 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
443 int fd;
444
445         /* Getting device status */
446
447 open_disk(u_flag)
448 {
449 struct 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
473 read_disk(sector, buf)
474 {
475         lseek(fd,(sector * 512), 0);
476         return read(fd, buf, 512);
477 }
478
479 write_disk(sector, buf)
480 {
481         lseek(fd,(sector * 512), 0);
482         return write(fd, buf, 512);
483 }
484
485 get_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 \f
501
502 read_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
517 write_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
544 ok(str)
545 char *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
559 decimal(str, num, deflt)
560 char *str;
561 int *num;
562 {
563 int acc = 0, c;
564 char *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
596 hex(str, num, deflt)
597 char *str;
598 int *num;
599 {
600 int acc = 0, c;
601 char *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
637 string(str, ans)
638 char *str;
639 char **ans;
640 {
641 int c;
642 char *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
668 char *get_type(type)
669 int     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 }