source: trunk/minix/commands/i386/mtools-3.9.7/mpartition.c@ 11

Last change on this file since 11 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 16.8 KB
RevLine 
[9]1/*
2 * mformat.c
3 */
4#define DONT_NEED_WAIT
5
6#include "sysincludes.h"
7#include "msdos.h"
8#include "mtools.h"
9#include "mainloop.h"
10#include "fsP.h"
11#include "file.h"
12#include "plain_io.h"
13#include "nameclash.h"
14#include "buffer.h"
15#include "scsi.h"
16#include "partition.h"
17
18#ifdef OS_linux
19#include "linux/hdreg.h"
20
21#define _LINUX_STRING_H_
22#define kdev_t int
23#include "linux/fs.h"
24#undef _LINUX_STRING_H_
25
26#endif
27
28#define tolinear(x) \
29(sector(x)-1+(head(x)+cyl(x)*used_dev->heads)*used_dev->sectors)
30
31
32static inline void print_hsc(hsc *h)
33{
34 printf(" h=%d s=%d c=%d\n",
35 head(*h), sector(*h), cyl(*h));
36}
37
38static void set_offset(hsc *h, int offset, int heads, int sectors)
39{
40 int head, sector, cyl;
41
42 if(! heads || !sectors)
43 head = sector = cyl = 0; /* linear mode */
44 else {
45 sector = offset % sectors;
46 offset = offset / sectors;
47
48 head = offset % heads;
49 cyl = offset / heads;
50 if(cyl > 1023) cyl = 1023;
51 }
52
53 h->head = head;
54 h->sector = ((sector+1) & 0x3f) | ((cyl & 0x300)>>2);
55 h->cyl = cyl & 0xff;
56}
57
58void setBeginEnd(struct partition *partTable, int begin, int end,
59 int heads, int sectors, int activate, int type)
60{
61 set_offset(&partTable->start, begin, heads, sectors);
62 set_offset(&partTable->end, end-1, heads, sectors);
63 set_dword(partTable->start_sect, begin);
64 set_dword(partTable->nr_sects, end-begin);
65 if(activate)
66 partTable->boot_ind = 0x80;
67 else
68 partTable->boot_ind = 0;
69 if(!type) {
70 if(end-begin < 4096)
71 type = 1; /* DOS 12-bit FAT */
72 else if(end-begin<32*2048)
73 type = 4; /* DOS 16-bit FAT, <32M */
74 else
75 type = 6; /* DOS 16-bit FAT >= 32M */
76 }
77 partTable->sys_ind = type;
78}
79
80int consistencyCheck(struct partition *partTable, int doprint, int verbose,
81 int *has_activated, int *last_end, int *j,
82 struct device *used_dev, int target_partition)
83{
84 int i;
85 int inconsistency;
86
87 *j = 0;
88 *last_end = 1;
89
90 /* quick consistency check */
91 inconsistency = 0;
92 *has_activated = 0;
93 for(i=1; i<5; i++){
94 if(!partTable[i].sys_ind)
95 continue;
96 if(partTable[i].boot_ind)
97 (*has_activated)++;
98 if((used_dev &&
99 (used_dev->heads != head(partTable[i].end)+1 ||
100 used_dev->sectors != sector(partTable[i].end))) ||
101 sector(partTable[i].start) != 1){
102 fprintf(stderr,
103 "Partition %d is not aligned\n",
104 i);
105 inconsistency=1;
106 }
107
108 if(*j && *last_end > BEGIN(partTable[i])) {
109 fprintf(stderr,
110 "Partitions %d and %d badly ordered or overlapping\n",
111 *j,i);
112 inconsistency=1;
113 }
114
115 *last_end = END(partTable[i]);
116 *j = i;
117
118 if(used_dev &&
119 cyl(partTable[i].start) != 1023 &&
120 tolinear(partTable[i].start) != BEGIN(partTable[i])) {
121 fprintf(stderr,
122 "Start position mismatch for partition %d\n",
123 i);
124 inconsistency=1;
125 }
126 if(used_dev &&
127 cyl(partTable[i].end) != 1023 &&
128 tolinear(partTable[i].end)+1 != END(partTable[i])) {
129 fprintf(stderr,
130 "End position mismatch for partition %d\n",
131 i);
132 inconsistency=1;
133 }
134
135 if(doprint && verbose) {
136 if(i==target_partition)
137 putchar('*');
138 else
139 putchar(' ');
140 printf("Partition %d\n",i);
141
142 printf(" active=%x\n", partTable[i].boot_ind);
143 printf(" start:");
144 print_hsc(&partTable[i].start);
145 printf(" type=0x%x\n", partTable[i].sys_ind);
146 printf(" end:");
147 print_hsc(&partTable[i].end);
148 printf(" start=%d\n", BEGIN(partTable[i]));
149 printf(" nr=%d\n", _DWORD(partTable[i].nr_sects));
150 printf("\n");
151 }
152 }
153 return inconsistency;
154}
155
156/* setsize function. Determines scsicam mapping if this cannot be inferred from
157 * any existing partitions. Shamelessly snarfed from the Linux kernel ;-) */
158
159/*
160 * Function : static int setsize(unsigned long capacity,unsigned int *cyls,
161 * unsigned int *hds, unsigned int *secs);
162 *
163 * Purpose : to determine a near-optimal int 0x13 mapping for a
164 * SCSI disk in terms of lost space of size capacity, storing
165 * the results in *cyls, *hds, and *secs.
166 *
167 * Returns : -1 on failure, 0 on success.
168 *
169 * Extracted from
170 *
171 * WORKING X3T9.2
172 * DRAFT 792D
173 *
174 *
175 * Revision 6
176 * 10-MAR-94
177 * Information technology -
178 * SCSI-2 Common access method
179 * transport and SCSI interface module
180 *
181 * ANNEX A :
182 *
183 * setsize() converts a read capacity value to int 13h
184 * head-cylinder-sector requirements. It minimizes the value for
185 * number of heads and maximizes the number of cylinders. This
186 * will support rather large disks before the number of heads
187 * will not fit in 4 bits (or 6 bits). This algorithm also
188 * minimizes the number of sectors that will be unused at the end
189 * of the disk while allowing for very large disks to be
190 * accommodated. This algorithm does not use physical geometry.
191 */
192
193static int setsize(unsigned long capacity,unsigned int *cyls,unsigned int *hds,
194 unsigned int *secs) {
195 unsigned int rv = 0;
196 unsigned long heads, sectors, cylinders, temp;
197
198 cylinders = 1024L; /* Set number of cylinders to max */
199 sectors = 62L; /* Maximize sectors per track */
200
201 temp = cylinders * sectors; /* Compute divisor for heads */
202 heads = capacity / temp; /* Compute value for number of heads */
203 if (capacity % temp) { /* If no remainder, done! */
204 heads++; /* Else, increment number of heads */
205 temp = cylinders * heads; /* Compute divisor for sectors */
206 sectors = capacity / temp; /* Compute value for sectors per
207 track */
208 if (capacity % temp) { /* If no remainder, done! */
209 sectors++; /* Else, increment number of sectors */
210 temp = heads * sectors; /* Compute divisor for cylinders */
211 cylinders = capacity / temp;/* Compute number of cylinders */
212 }
213 }
214 if (cylinders == 0) rv=(unsigned)-1;/* Give error if 0 cylinders */
215
216 *cyls = (unsigned int) cylinders; /* Stuff return values */
217 *secs = (unsigned int) sectors;
218 *hds = (unsigned int) heads;
219 return(rv);
220}
221
222static void setsize0(unsigned long capacity,unsigned int *cyls,
223 unsigned int *hds, unsigned int *secs)
224{
225 int r;
226
227 /* 1. First try "Megabyte" sizes */
228 if(capacity < 1024 * 2048 && !(capacity % 1024)) {
229 *cyls = capacity >> 11;
230 *hds = 64;
231 *secs = 32;
232 return;
233 }
234
235 /* then try scsicam's size */
236 r = setsize(capacity,cyls,hds,secs);
237 if(r || *hds > 255 || *secs > 63) {
238 /* scsicam failed. Do megabytes anyways */
239 *cyls = capacity >> 11;
240 *hds = 64;
241 *secs = 32;
242 return;
243 }
244}
245
246
247static void usage(void)
248{
249 fprintf(stderr,
250 "Mtools version %s, dated %s\n", mversion, mdate);
251 fprintf(stderr,
252 "Usage: %s [-pradcv] [-I [-B bootsect-template] [-s sectors] "
253 "[-t cylinders] "
254 "[-h heads] [-T type] [-b begin] [-l length] "
255 "drive\n", progname);
256 exit(1);
257}
258
259void mpartition(int argc, char **argv, int dummy)
260{
261 Stream_t *Stream;
262 unsigned int dummy2;
263
264 int i,j;
265
266 int sec_per_cyl;
267 int doprint = 0;
268 int verbose = 0;
269 int create = 0;
270 int force = 0;
271 int length = 0;
272 int remove = 0;
273 int initialize = 0;
274 int tot_sectors=0;
275 int type = 0;
276 int begin_set = 0;
277 int size_set = 0;
278 int end_set = 0;
279 int last_end = 0;
280 int activate = 0;
281 int has_activated = 0;
282 int inconsistency=0;
283 int begin=0;
284 int end=0;
285 int sizetest=0;
286 int dirty = 0;
287 int open2flags = NO_OFFSET;
288
289 int c;
290 struct device used_dev;
291 int argtracks, argheads, argsectors;
292
293 char *drive, name[EXPAND_BUF];
294 unsigned char buf[512];
295 struct partition *partTable=(struct partition *)(buf+ 0x1ae);
296 struct device *dev;
297 char errmsg[200];
298 char *bootSector=0;
299
300 argtracks = 0;
301 argheads = 0;
302 argsectors = 0;
303
304 /* get command line options */
305 while ((c = getopt(argc, argv, "adprcIT:t:h:s:fvpb:l:S:B:")) != EOF) {
306 switch (c) {
307 case 'B':
308 bootSector = optarg;
309 break;
310 case 'a':
311 /* no privs, as it could be abused to
312 * make other partitions unbootable, or
313 * to boot a rogue kernel from this one */
314 open2flags |= NO_PRIV;
315 activate = 1;
316 dirty = 1;
317 break;
318 case 'd':
319 activate = -1;
320 dirty = 1;
321 break;
322 case 'p':
323 doprint = 1;
324 break;
325 case 'r':
326 remove = 1;
327 dirty = 1;
328 break;
329 case 'I':
330 /* could be abused to nuke all other
331 * partitions */
332 open2flags |= NO_PRIV;
333 initialize = 1;
334 dirty = 1;
335 break;
336 case 'c':
337 create = 1;
338 dirty = 1;
339 break;
340
341 case 'T':
342 /* could be abused to "manually" create
343 * extended partitions */
344 open2flags |= NO_PRIV;
345 type = strtoul(optarg,0,0);
346 break;
347
348 case 't':
349 argtracks = atoi(optarg);
350 break;
351 case 'h':
352 argheads = atoi(optarg);
353 break;
354 case 's':
355 argsectors = atoi(optarg);
356 break;
357
358 case 'f':
359 /* could be abused by creating overlapping
360 * partitions and other such Snafu */
361 open2flags |= NO_PRIV;
362 force = 1;
363 break;
364
365 case 'v':
366 verbose++;
367 break;
368 case 'S':
369 /* testing only */
370 /* could be abused to create partitions
371 * extending beyond the actual size of the
372 * device */
373 open2flags |= NO_PRIV;
374 tot_sectors = strtoul(optarg,0,0);
375 sizetest = 1;
376 break;
377 case 'b':
378 begin_set = 1;
379 begin = atoi(optarg);
380 break;
381 case 'l':
382 size_set = 1;
383 length = atoi(optarg);
384 break;
385
386 default:
387 usage();
388 }
389 }
390
391 if (argc - optind != 1 || skip_drive(argv[optind]) == argv[optind])
392 usage();
393
394 drive = get_drive(argv[optind], NULL);
395
396 /* check out a drive whose letter and parameters match */
397 sprintf(errmsg, "Drive '%s:' not supported", drive);
398 Stream = 0;
399 for(dev=devices;dev->drive;dev++) {
400 FREE(&(Stream));
401 /* drive letter */
402 if (strcmp(dev->drive, drive) != 0)
403 continue;
404 if (dev->partition < 1 || dev->partition > 4) {
405 sprintf(errmsg,
406 "Drive '%c:' is not a partition",
407 drive);
408 continue;
409 }
410 used_dev = *dev;
411
412 SET_INT(used_dev.tracks, argtracks);
413 SET_INT(used_dev.heads, argheads);
414 SET_INT(used_dev.sectors, argsectors);
415
416 expand(dev->name, name);
417 Stream = SimpleFileOpen(&used_dev, dev, name,
418 dirty ? O_RDWR : O_RDONLY,
419 errmsg, open2flags, 1, 0);
420
421 if (!Stream) {
422#ifdef HAVE_SNPRINTF
423 snprintf(errmsg,199,"init: open: %s", strerror(errno));
424#else
425 sprintf(errmsg,"init: open: %s", strerror(errno));
426#endif
427 continue;
428 }
429
430
431 /* try to find out the size */
432 if(!sizetest)
433 tot_sectors = 0;
434 if(IS_SCSI(dev)) {
435 unsigned char cmd[10];
436 unsigned char data[10];
437 cmd[0] = SCSI_READ_CAPACITY;
438 memset ((void *) &cmd[2], 0, 8);
439 memset ((void *) &data[0], 137, 10);
440 scsi_cmd(get_fd(Stream), cmd, 10, SCSI_IO_READ,
441 data, 10, get_extra_data(Stream));
442
443 tot_sectors = 1 +
444 (data[0] << 24) +
445 (data[1] << 16) +
446 (data[2] << 8) +
447 (data[3] );
448 if(verbose)
449 printf("%d sectors in total\n", tot_sectors);
450 }
451
452#ifdef OS_linux
453 if (tot_sectors == 0) {
454 ioctl(get_fd(Stream), BLKGETSIZE, &tot_sectors);
455 }
456#endif
457
458 /* read the partition table */
459 if (READS(Stream, (char *) buf, 0, 512) != 512) {
460#ifdef HAVE_SNPRINTF
461 snprintf(errmsg, 199,
462 "Error reading from '%s', wrong parameters?",
463 name);
464#else
465 sprintf(errmsg,
466 "Error reading from '%s', wrong parameters?",
467 name);
468#endif
469 continue;
470 }
471 if(verbose>=2)
472 print_sector("Read sector", buf, 512);
473 break;
474 }
475
476 /* print error msg if needed */
477 if ( dev->drive == 0 ){
478 FREE(&Stream);
479 fprintf(stderr,"%s: %s\n", argv[0],errmsg);
480 exit(1);
481 }
482
483 if((used_dev.sectors || used_dev.heads) &&
484 (!used_dev.sectors || !used_dev.heads)) {
485 fprintf(stderr,"You should either indicate both the number of sectors and the number of heads,\n");
486 fprintf(stderr," or none of them\n");
487 exit(1);
488 }
489
490 if(initialize) {
491 if (bootSector) {
492 int fd;
493 fd = open(bootSector, O_RDONLY);
494 if (fd < 0) {
495 perror("open boot sector");
496 exit(1);
497 }
498 read(fd, (char *) buf, 512);
499 }
500 memset((char *)(partTable+1), 0, 4*sizeof(*partTable));
501 set_dword(((unsigned char*)buf)+510, 0xaa55);
502 }
503
504 /* check for boot signature, and place it if needed */
505 if((buf[510] != 0x55) || (buf[511] != 0xaa)) {
506 fprintf(stderr,"Boot signature not set\n");
507 fprintf(stderr,
508 "Use the -I flag to initialize the partition table, and set the boot signature\n");
509 inconsistency = 1;
510 }
511
512 if(remove){
513 if(!partTable[dev->partition].sys_ind)
514 fprintf(stderr,
515 "Partition for drive %c: does not exist\n",
516 drive);
517 if((partTable[dev->partition].sys_ind & 0x3f) == 5) {
518 fprintf(stderr,
519 "Partition for drive %c: may be an extended partition\n",
520 drive);
521 fprintf(stderr,
522 "Use the -f flag to remove it anyways\n");
523 inconsistency = 1;
524 }
525 memset(&partTable[dev->partition], 0, sizeof(*partTable));
526 }
527
528 if(create && partTable[dev->partition].sys_ind) {
529 fprintf(stderr,
530 "Partition for drive %c: already exists\n", drive);
531 fprintf(stderr,
532 "Use the -r flag to remove it before attempting to recreate it\n");
533 }
534
535
536 /* find out number of heads and sectors, and whether there is
537 * any activated partition */
538 has_activated = 0;
539 for(i=1; i<5; i++){
540 if(!partTable[i].sys_ind)
541 continue;
542
543 if(partTable[i].boot_ind)
544 has_activated++;
545
546 /* set geometry from entry */
547 if (!used_dev.heads)
548 used_dev.heads = head(partTable[i].end)+1;
549 if(!used_dev.sectors)
550 used_dev.sectors = sector(partTable[i].end);
551 if(i<dev->partition && !begin_set)
552 begin = END(partTable[i]);
553 if(i>dev->partition && !end_set && !size_set) {
554 end = BEGIN(partTable[i]);
555 end_set = 1;
556 }
557 }
558
559#ifdef OS_linux
560 if(!used_dev.sectors && !used_dev.heads) {
561 if(!IS_SCSI(dev)) {
562 struct hd_geometry geom;
563 if(ioctl(get_fd(Stream), HDIO_GETGEO, &geom) == 0) {
564 used_dev.heads = geom.heads;
565 used_dev.sectors = geom.sectors;
566 }
567 }
568 }
569#endif
570
571 if(!used_dev.sectors && !used_dev.heads) {
572 if(tot_sectors)
573 setsize0(tot_sectors,&dummy2,&used_dev.heads,
574 &used_dev.sectors);
575 else {
576 used_dev.heads = 64;
577 used_dev.sectors = 32;
578 }
579 }
580
581 if(verbose)
582 fprintf(stderr,"sectors: %d heads: %d %d\n",
583 used_dev.sectors, used_dev.heads, tot_sectors);
584
585 sec_per_cyl = used_dev.sectors * used_dev.heads;
586 if(create) {
587 if(!end_set && tot_sectors) {
588 end = tot_sectors - tot_sectors % sec_per_cyl;
589 end_set = 1;
590 }
591
592 /* if the partition starts right at the beginning of
593 * the disk, keep one track unused to allow place for
594 * the master boot record */
595 if(!begin && !begin_set)
596 begin = used_dev.sectors;
597 if(!size_set && used_dev.tracks) {
598 size_set = 2;
599 length = sec_per_cyl * used_dev.tracks;
600
601 /* round the size in order to take
602 * into account any "hidden" sectors */
603
604 /* do we anchor this at the beginning ?*/
605 if(begin_set || dev->partition <= 2 || !end_set)
606 length -= begin % sec_per_cyl;
607 else if(end - length < begin)
608 /* truncate any overlap */
609 length = end - begin;
610 }
611 if(size_set) {
612 if(!begin_set && dev->partition >2 && end_set)
613 begin = end - length;
614 else
615 end = begin + length;
616 } else if(!end_set) {
617 fprintf(stderr,"Unknown size\n");
618 exit(1);
619 }
620
621 setBeginEnd(&partTable[dev->partition], begin, end,
622 used_dev.heads, used_dev.sectors,
623 !has_activated, type);
624 }
625
626 if(activate) {
627 if(!partTable[dev->partition].sys_ind) {
628 fprintf(stderr,
629 "Partition for drive %c: does not exist\n",
630 drive);
631 } else {
632 switch(activate) {
633 case 1:
634 partTable[dev->partition].boot_ind=0x80;
635 break;
636 case -1:
637 partTable[dev->partition].boot_ind=0x00;
638 break;
639 }
640 }
641 }
642
643
644 inconsistency |= consistencyCheck(partTable, doprint, verbose,
645 &has_activated, &last_end, &j,
646 &used_dev, dev->partition);
647
648 if(doprint && !inconsistency && partTable[dev->partition].sys_ind) {
649 printf("The following command will recreate the partition for drive %c:\n",
650 drive);
651 used_dev.tracks =
652 (_DWORD(partTable[dev->partition].nr_sects) +
653 (BEGIN(partTable[dev->partition]) % sec_per_cyl)) /
654 sec_per_cyl;
655 printf("mpartition -c -t %d -h %d -s %d -b %u %c:\n",
656 used_dev.tracks, used_dev.heads, used_dev.sectors,
657 BEGIN(partTable[dev->partition]), drive);
658 }
659
660 if(tot_sectors && last_end >tot_sectors) {
661 fprintf(stderr,
662 "Partition %d exceeds beyond end of disk\n",
663 j);
664 exit(1);
665 }
666
667
668 switch(has_activated) {
669 case 0:
670 fprintf(stderr,
671 "Warning: no active (bootable) partition present\n");
672 break;
673 case 1:
674 break;
675 default:
676 fprintf(stderr,
677 "Warning: %d active (bootable) partitions present\n",
678 has_activated);
679 fprintf(stderr,
680 "Usually, a disk should have exactly one active partition\n");
681 break;
682 }
683
684 if(inconsistency && !force) {
685 fprintf(stderr,
686 "inconsistency detected!\n" );
687 if(dirty)
688 fprintf(stderr,
689 "Retry with the -f switch to go ahead anyways\n");
690 exit(1);
691 }
692
693 if(dirty) {
694 /* write data back to the disk */
695 if(verbose>=2)
696 print_sector("Writing sector", buf, 512);
697 if (WRITES(Stream, (char *) buf, 0, 512) != 512) {
698 fprintf(stderr,"Error writing partition table");
699 exit(1);
700 }
701 if(verbose>=3)
702 print_sector("Sector written", buf, 512);
703 FREE(&Stream);
704 }
705 exit(0);
706}
Note: See TracBrowser for help on using the repository browser.