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