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