fdisk.c revision 1.1 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 (at) 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
125 struct part_type
127 {
128 unsigned char type;
129 char *name;
130 }part_types[] =
131 {
132 {0x00, "unused"}
133 ,{0x01, "Primary DOS with 12 bit FAT"}
134 ,{0x02, "XENIX / filesystem"}
135 ,{0x03, "XENIX /usr filesystem"}
136 ,{0x04, "Primary DOS with 16 bit FAT"}
137 ,{0x05, "Extended DOS"}
138 ,{0x06, "Primary 'big' DOS (> 32MB)"}
139 ,{0x07, "OS/2 HPFS, QNX or Advanced UNIX"}
140 ,{0x08, "AIX filesystem"}
141 ,{0x09, "AIX boot partition or Coherent"}
142 ,{0x0A, "OS/2 Boot Manager or OPUS"}
143 ,{0x10, "OPUS"}
144 ,{0x40, "VENIX 286"}
145 ,{0x50, "DM"}
146 ,{0x51, "DM"}
147 ,{0x52, "CP/M or Microport SysV/AT"}
148 ,{0x56, "GB"}
149 ,{0x61, "Speed"}
150 ,{0x63, "ISC UNIX, other System V/386, GNU HURD or Mach"}
151 ,{0x64, "Novell Netware 2.xx"}
152 ,{0x65, "Novell Netware 3.xx"}
153 ,{0x75, "PCIX"}
154 ,{0x80, "Minix 1.1 ... 1.4a"}
155 ,{0x81, "Minix 1.4b ... 1.5.10"}
156 ,{0x82, "Linux"}
157 ,{0x93, "Amoeba filesystem"}
158 ,{0x94, "Amoeba bad block table"}
159 ,{0xA5, "386BSD"}
160 ,{0xB7, "BSDI BSD/386 filesystem"}
161 ,{0xB8, "BSDI BSD/386 swap"}
162 ,{0xDB, "Concurrent CPM or C.DOS or CTOS"}
163 ,{0xE1, "Speed"}
164 ,{0xE3, "Speed"}
165 ,{0xE4, "Speed"}
166 ,{0xF1, "Speed"}
167 ,{0xF2, "DOS 3.3+ Secondary"}
168 ,{0xF4, "Speed"}
169 ,{0xFF, "BBT (Bad Blocks Table)"}
170 };
171
172
173 main(argc, argv)
174 char **argv;
175 {
176 int i;
177
178 name = *argv;
179 {register char *cp = name;
180 while (*cp) if (*cp++ == '/') name = cp;
181 }
182
183 for ( argv++ ; --argc ; argv++ ) { register char *token = *argv;
184 if (*token++ != '-' || !*token)
185 break;
186 else { register int flag;
187 for ( ; flag = *token++ ; ) {
188 switch (flag) {
189 case '0':
190 partition = 0;
191 break;
192 case '1':
193 partition = 1;
194 break;
195 case '2':
196 partition = 2;
197 break;
198 case '3':
199 partition = 3;
200 break;
201 case 'a':
202 a_flag = 1;
203 break;
204 case 'i':
205 i_flag = 1;
206 case 'u':
207 u_flag = 1;
208 break;
209 default:
210 goto usage;
211 }
212 }
213 }
214 }
215
216 if (argc > 0)
217 disk = argv[0];
218
219 if (open_disk(u_flag) < 0)
220 exit(1);
221
222 printf("******* Working on device %s *******\n",disk);
223 if(u_flag)
224 {
225 get_params_to_use();
226 }
227 else
228 {
229 print_params();
230 }
231
232 if (read_s0())
233 init_sector0(1);
234
235 printf("Warning: BIOS sector numbering starts with sector 1\n");
236 printf("Information from DOS bootblock is:\n");
237 if (partition == -1)
238 for (i = 0; i < NDOSPART; i++)
239 change_part(i);
240 else
241 change_part(partition);
242
243 if (u_flag || a_flag)
244 change_active(partition);
245
246 if (u_flag || a_flag) {
247 printf("\nWe haven't changed the partition table yet. ");
248 printf("This is your last chance.\n");
249 print_s0(-1);
250 if (ok("Should we write new partition table?"))
251 write_s0();
252 }
253
254 exit(0);
255
256 usage:
257 printf("fdisk {-a|-i|-r} {disk}\n");
258 }
259
260 print_s0(which)
261 {
262 int i;
263
264 print_params();
265 printf("Information from DOS bootblock is:\n");
266 if (which == -1)
267 for (i = 0; i < NDOSPART; i++)
268 printf("%d: ", i), print_part(i);
269 else
270 print_part(which);
271 }
272
273 static struct dos_partition mtpart = { 0 };
274
275 print_part(i)
276 {
277 struct dos_partition *partp = ((struct dos_partition *) &mboot.parts) + i;
278
279
280 if (!bcmp(partp, &mtpart, sizeof (struct dos_partition))) {
281 printf("<UNUSED>\n");
282 return;
283 }
284 printf("sysid %d,(%s)\n", partp->dp_typ, get_type(partp->dp_typ));
285 printf(" start %d, size %d (%d Meg), flag %x\n",
286 partp->dp_start,
287 partp->dp_size, partp->dp_size * 512 / (1024 * 1024),
288 partp->dp_flag);
289 printf("\tbeg: cyl %d/ sector %d/ head %d;\n\tend: cyl %d/ sector %d/ head %d\n"
290 ,DPCYL(partp->dp_scyl, partp->dp_ssect)
291 ,DPSECT(partp->dp_ssect)
292 ,partp->dp_shd
293 ,DPCYL(partp->dp_ecyl, partp->dp_esect)
294 ,DPSECT(partp->dp_esect)
295 ,partp->dp_ehd);
296 }
297
298 init_sector0(start)
299 {
300 struct dos_partition *partp = (struct dos_partition *) (&mboot.parts[3]);
301 int size = disksecs - start;
302 int rest;
303
304 memcpy(mboot.bootinst, bootcode, sizeof(bootcode));
305 mboot.signature = BOOT_MAGIC;
306
307 partp->dp_typ = DOSPTYP_386BSD;
308 partp->dp_flag = ACTIVE;
309 partp->dp_start = start;
310 partp->dp_size = size;
311
312 dos(partp->dp_start, &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd);
313 dos(partp->dp_start+partp->dp_size, &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd);
314 }
315
316 change_part(i)
317 {
318 struct dos_partition *partp = ((struct dos_partition *) &mboot.parts) + i;
319
320 printf("The data for partition %d is:\n", i);
321 print_part(i);
322
323 if (u_flag && ok("Do you want to change it?")) {
324 int tmp;
325
326 if (i_flag) {
327 bzero((char *)partp, sizeof (struct dos_partition));
328 if (i == 3) {
329 init_sector0(1);
330 printf("\nThe static data for the DOS partition 3 has been reinitialized to:\n");
331 print_part(i);
332 }
333 }
334
335 do {
336 Decimal("sysid", partp->dp_typ, tmp);
337 Decimal("start", partp->dp_start, tmp);
338 Decimal("size", partp->dp_size, tmp);
339
340 if (ok("Explicitly specifiy beg/end address ?"))
341 {
342 int tsec,tcyl,thd;
343 tcyl = DPCYL(partp->dp_scyl,partp->dp_ssect);
344 thd = partp->dp_shd;
345 tsec = DPSECT(partp->dp_ssect);
346 Decimal("beginning cylinder", tcyl, tmp);
347 Decimal("beginning head", thd, tmp);
348 Decimal("beginning sector", tsec, tmp);
349 partp->dp_scyl = DOSCYL(tcyl);
350 partp->dp_ssect = DOSSECT(tsec,tcyl);
351 partp->dp_shd = thd;
352
353 tcyl = DPCYL(partp->dp_ecyl,partp->dp_esect);
354 thd = partp->dp_ehd;
355 tsec = DPSECT(partp->dp_esect);
356 Decimal("ending cylinder", tcyl, tmp);
357 Decimal("ending head", thd, tmp);
358 Decimal("ending sector", tsec, tmp);
359 partp->dp_ecyl = DOSCYL(tcyl);
360 partp->dp_esect = DOSSECT(tsec,tcyl);
361 partp->dp_ehd = thd;
362 } else {
363 dos(partp->dp_start,
364 &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd);
365 dos(partp->dp_start+partp->dp_size - 1,
366 &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd);
367 }
368
369 print_part(i);
370 } while (!ok("Are we happy with this entry?"));
371 }
372 }
373
374 print_params()
375 {
376 printf("parameters extracted from in-core disklabel are:\n");
377 printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n"
378 ,cyls,heads,sectors,cylsecs);
379 if((dos_sectors > 63) || (dos_cyls > 1023) || (dos_heads > 255))
380 printf(" Figures below won't work with BIOS for partitions not in cyl 1\n");
381 printf("parameters to be used for BIOS calculations are:\n");
382 printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n"
383 ,dos_cyls,dos_heads,dos_sectors,dos_cylsecs);
384 }
385
386 change_active(which)
387 {
388 int i;
389 int active = 3, tmp;
390 struct dos_partition *partp = ((struct dos_partition *) &mboot.parts);
391
392 if (a_flag && which != -1)
393 active = which;
394 if (ok("Do you want to change the active partition?")) {
395 do
396 Decimal("active partition", active, tmp);
397 while(!ok("Are you happy with this choice"));
398 }
399 for (i = 0; i < NDOSPART; i++)
400 partp[i].dp_flag = 0;
401 partp[active].dp_flag = ACTIVE;
402 }
403
404 get_params_to_use()
405 {
406 int tmp;
407 print_params();
408 if (ok("Do you want to change our idea of what BIOS thinks ?"))
409 {
410 do
411 {
412 Decimal("BIOS's idea of #cylinders", dos_cyls, tmp);
413 Decimal("BIOS's idea of #heads", dos_heads, tmp);
414 Decimal("BIOS's idea of #sectors", dos_sectors, tmp);
415 dos_cylsecs = dos_heads * dos_sectors;
416 print_params();
417 }
418 while(!ok("Are you happy with this choice"));
419 }
420 }
421
422 /***********************************************\
423 * Change real numbers into strange dos numbers *
424 \***********************************************/
425 static
426 dos(sec, c, s, h)
427 int sec;
428 unsigned char *c, *s, *h;
429 {
430 int cy;
431 int hd;
432
433 cy = sec / ( dos_cylsecs );
434 sec = sec - cy * ( dos_cylsecs );
435
436 hd = sec / dos_sectors;
437 sec = (sec - hd * dos_sectors) + 1;
438
439 *h = hd;
440 *c = cy & 0xff;
441 *s = (sec & 0x3f) | ( (cy & 0x300) >> 2);
442 }
443
444 int fd;
445
446 /* Getting device status */
447
448 open_disk(u_flag)
449 {
450 struct stat st;
451
452 if (stat(disk, &st) == -1) {
453 fprintf(stderr, "%s: Can't get file status of %s\n",
454 name, disk);
455 return -1;
456 } else if ( !(st.st_mode & S_IFCHR) ) {
457 fprintf(stderr,"%s: Device %s is not character special\n",
458 name, disk);
459 return -1;
460 }
461 if ((fd = open(disk, u_flag?O_RDWR:O_RDONLY)) == -1) {
462 fprintf(stderr,"%s: Can't open device %s\n", name, disk);
463 return -1;
464 }
465 if (get_params(0) == -1) {
466 fprintf(stderr, "%s: Can't get disk parameters on %s\n",
467 name, disk);
468 return -1;
469 }
470 return fd;
471 }
472
473
474 read_disk(sector, buf)
475 {
476 lseek(fd,(sector * 512), 0);
477 return read(fd, buf, 512);
478 }
479
480 write_disk(sector, buf)
481 {
482 lseek(fd,(sector * 512), 0);
483 return write(fd, buf, 512);
484 }
485
486 get_params(verbose)
487 {
488
489 if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) {
490 return -1;
491 }
492
493 dos_cyls = cyls = disklabel.d_ncylinders;
494 dos_heads = heads = disklabel.d_ntracks;
495 dos_sectors = sectors = disklabel.d_nsectors;
496 dos_cylsecs = cylsecs = heads * sectors;
497 disksecs = cyls * heads * sectors;
498
499 return (disksecs);
500 }
501
502
504 read_s0()
505 {
506 if (read_disk(0, (char *) mboot.bootinst) == -1) {
507 fprintf(stderr, "%s: Can't read fdisk partition table\n", name);
508 return -1;
509 }
510 if (mboot.signature != BOOT_MAGIC) {
511 fprintf(stderr, "%s: Invalid fdisk partition table found\n",
512 name);
513 /* So should we initialize things */
514 return -1;
515 }
516 return 0;
517 }
518
519 write_s0()
520 {
521 int flag;
522 if (iotest) {
523 print_s0(-1);
524 return 0;
525 }
526 /*
527 * write enable label sector before write (if necessary),
528 * disable after writing.
529 * needed if the disklabel protected area also protects
530 * sector 0. (e.g. empty disk)
531 */
532 flag = 1;
533 if (ioctl(fd, DIOCWLABEL, &flag) < 0)
534 perror("ioctl DIOCWLABEL");
535 if (write_disk(0, (char *) mboot.bootinst) == -1) {
536 fprintf(stderr, "%s: Can't write fdisk partition table\n",
537 name);
538 return -1;
539 flag = 0;
540 (void) ioctl(fd, DIOCWLABEL, &flag);
541 }
542 }
543
544
545
546 ok(str)
547 char *str;
548 {
549 printf("%s [n] ", str);
550 fgets(lbuf, LBUF, stdin);
551 lbuf[strlen(lbuf)-1] = 0;
552
553 if (*lbuf &&
554 (!strcmp(lbuf, "yes") || !strcmp(lbuf, "YES") ||
555 !strcmp(lbuf, "y") || !strcmp(lbuf, "Y")))
556 return 1;
557 else
558 return 0;
559 }
560
561 decimal(str, num, deflt)
562 char *str;
563 int *num;
564 {
565 int acc = 0, c;
566 char *cp;
567
568 while (1) {
569 printf("Supply a decimal value for \"%s\" [%d] ", str, deflt);
570 fgets(lbuf, LBUF, stdin);
571 lbuf[strlen(lbuf)-1] = 0;
572
573 if (!*lbuf)
574 return 0;
575
576 cp = lbuf;
577 while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
578 if (!c)
579 return 0;
580 while (c = *cp++) {
581 if (c <= '9' && c >= '0')
582 acc = acc * 10 + c - '0';
583 else
584 break;
585 }
586 if (c == ' ' || c == '\t')
587 while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
588 if (!c) {
589 *num = acc;
590 return 1;
591 } else
592 printf("%s is an invalid decimal number. Try again\n",
593 lbuf);
594 }
595
596 }
597
598 hex(str, num, deflt)
599 char *str;
600 int *num;
601 {
602 int acc = 0, c;
603 char *cp;
604
605 while (1) {
606 printf("Supply a hex value for \"%s\" [%x] ", str, deflt);
607 fgets(lbuf, LBUF, stdin);
608 lbuf[strlen(lbuf)-1] = 0;
609
610 if (!*lbuf)
611 return 0;
612
613 cp = lbuf;
614 while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
615 if (!c)
616 return 0;
617 while (c = *cp++) {
618 if (c <= '9' && c >= '0')
619 acc = (acc << 4) + c - '0';
620 else if (c <= 'f' && c >= 'a')
621 acc = (acc << 4) + c - 'a' + 10;
622 else if (c <= 'F' && c >= 'A')
623 acc = (acc << 4) + c - 'A' + 10;
624 else
625 break;
626 }
627 if (c == ' ' || c == '\t')
628 while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
629 if (!c) {
630 *num = acc;
631 return 1;
632 } else
633 printf("%s is an invalid hex number. Try again\n",
634 lbuf);
635 }
636
637 }
638
639 string(str, ans)
640 char *str;
641 char **ans;
642 {
643 int c;
644 char *cp = lbuf;
645
646 while (1) {
647 printf("Supply a string value for \"%s\" [%s] ", str, *ans);
648 fgets(lbuf, LBUF, stdin);
649 lbuf[strlen(lbuf)-1] = 0;
650
651 if (!*lbuf)
652 return 0;
653
654 while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
655 if (c == '"') {
656 c = *++cp;
657 *ans = cp;
658 while ((c = *cp) && c != '"') cp++;
659 } else {
660 *ans = cp;
661 while ((c = *cp) && c != ' ' && c != '\t') cp++;
662 }
663
664 if (c)
665 *cp = 0;
666 return 1;
667 }
668 }
669
670 char *get_type(type)
671 int type;
672 {
673 int numentries = (sizeof(part_types)/sizeof(struct part_type));
674 int counter = 0;
675 struct part_type *ptr = part_types;
676
677
678 while(counter < numentries)
679 {
680 if(ptr->type == type)
681 {
682 return(ptr->name);
683 }
684 ptr++;
685 counter++;
686 }
687 return("unknown");
688 }
689