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